当前位置:网站首页>Several methods of initializing singleton variable in go language

Several methods of initializing singleton variable in go language

2020-11-09 12:25:19 Snow mountain flying pig

Pre initialize

On the outside var initialization

package main

import (
    "fmt"
    "time"
)

var startTime = time.Now()

func main() {
    fmt.Println(startTime)
}

stay init Function initialization

package main

import (
    "fmt"
    "time"
)

var startTime time.Time

func init() {
    startTime = time.Now()
}

func main() {
    fmt.Println(startTime)
}

stay main Function performs a custom initialization function

package main

import (
    "fmt"
    "time"
)

var startTime time.Time

func initApp() {
    startTime = time.Now()
}

func main() {
    initApp()
    fmt.Println(startTime)
}

Delayed loading is initialized only once ( Single case )

Lock implementation

Although it meets the requirements , But there are performance problems , Because every time the requester has to compete for the lock to read the connection
In fact, after creating the connection , You don't need a lock


var connMu sync.Mutex
var conn net.Conn

func getConn() net.Conn {
    connMu.Lock()
    defer connMu.Unlock()

    if conn != nil {
        return conn
    }
    conn,_ = net.DialTimeout("tcp","baidu.com:80",10*time.Second)
    return conn
}

func main() {
    conn := getConn()
    if conn != nil {
        panic("conn is nil")
    }
}

Standard library Once Realization

package main

import (
    "net"
    "sync"
)

var conn net.Conn
var once sync.Once

func getConn() net.Conn {
    var err error
    once.Do(func() {
        conn, err = net.Dial("tcp", "baidu.com")
    })
    return conn
}

func main() {
    conn := getConn()
    if conn != nil {
        panic("conn is nil")
    }
}

Customize Once Realization

Once There is a flaw in the logic of implementation , Is that when f After function initialization failed , It won't be implemented again , We can actually be in Once When f Function does not return error When the initialization is complete
in addition , We can also go back to Done Whether the prosecution has been initialized

package main

import (
    "errors"
    "fmt"
    "sync"
    "sync/atomic"
)

type Once struct {
    done uint32
    m sync.Mutex
}

func (o *Once) Do(f func() error) error {
    if atomic.LoadUint32(&o.done) == 0 {
        return o.doSlow(f)
    }
    return nil
}

func (o *Once) doSlow(f func() error) (err error) {
    o.m.Lock()
    defer o.m.Unlock()
    if o.done == 0 {
        if err = f(); err == nil {
            defer atomic.StoreUint32(&o.done, 1)
        }
    }
    return err
}
// Add another judgment Once Whether the implementation is completed 
func (o *Once) Done() bool {
    return atomic.LoadUint32(&o.done) == 1
}

func main() {
    var once Once
    once.Do(func() error {
        fmt.Println("one")
        return errors.New("one error")
    })
    fmt.Println(once.Done())
    once.Do(func() error {
        fmt.Println("two")
        return nil
    })
    fmt.Println(once.Done())
}

版权声明
本文为[Snow mountain flying pig]所创,转载请带上原文链接,感谢