首页 > 编程笔记 > Go语言笔记 阅读:2

Go语言sync.Once的用法(附带实例)

在 Go语言中,init() 函数和 sync.Once 都用于确保某些代码只执行一次。但它们的性质和用途有所不同。

init() 是一个特殊的函数,它在每个包被加载时自动执行,通常用于初始化包级别的变量或执行其他只需要执行一次的初始化任务。init() 函数不需要被显式调用,Go 程序运行时会自动调用它们。

sync.Once 是一个提供了 Do() 方法的结构体,它接受一个无参数、无返回值的函数,并确保这个函数在程序运行期间只被执行一次。sync.Once 主要用于代码中的懒加载(即在首次使用时才初始化)或确保并发安全的单次初始化。

sync.Once 的结构体及其方法如下:
type Once struct {
   m    Mutex
   done uint32
}
 
func (o *Once) Do(f func())
其中,成员 done 用来记录执行的次数,成员 m 是一个互斥锁,用来确保函数仅被执行一次。sync.Once 只有一个方法 Do(),尽管可以多次调用方法 Do(),但仅在第一次调用时参数 f 对应的函数会被执行,后面即使传入的参数f的值和前面不一样,也不会再次执行。这里f的值是一个无参数无返回值的函数。

sync.Once 常被用于单例模式的初始化场景中。下面的示例分别展示了传统的和使用 sync.Once 实现单例模式的方法。
type MySQLConfig struct {
        URL string
}
 
var config *MySQLConfig
var mu sync.Mutex
 
//传统实现单例模式的方法
func GetMyConfig() *MySQLConfig  {
        mu.Lock()
        defer mu.Unlock()
        if config!=nil{
                return  config
        }else{
                config =  new(MySQLConfig)
        }
        return config
}
 
//利用sync.Once实现单例模式
var once sync.Once
func GetMyConfig() *MySQLConfig  {
        once.Do(func() {
                config = new(MySQLConfig)
        })
        return config
}

相关文章