什么是 sync.Once
?
sync.Once
是 Go 标准库中的一个结构体,用于确保某些代码只执行一次,无论有多少 goroutine 并发调用。它提供了一个线程安全的机制,保证初始化操作或某些关键代码只执行一次。
通俗解释
可以把 sync.Once
想象成一个保险丝:
- 第一次触发时,保险丝烧断,代码被执行。
- 后续触发时,因为保险丝已烧断,代码不再重复执行。
例如:
- 初始化数据库连接。
- 加载配置文件。
- 设置全局变量。
核心方法
sync.Once
的核心方法是:
Do(func())
:接受一个函数作为参数,保证这个函数只执行一次。
使用示例
1. 单次初始化
package mainimport ("fmt""sync"
)var once sync.Oncefunc initialize() {fmt.Println("Initializing...")
}func main() {for i := 0; i < 5; i++ {go once.Do(initialize)}// 等待所有 goroutine 执行完成fmt.Scanln()
}
输出结果:
Initializing...
说明:
- 无论有多少 goroutine 并发调用
once.Do(initialize)
,initialize()
只会执行一次。
2. 应用场景:单例模式
在 Go 中,sync.Once
常用于实现单例模式,确保某个对象只被初始化一次:
package mainimport ("fmt""sync"
)var instance *Singleton
var once sync.Oncetype Singleton struct{}func GetInstance() *Singleton {once.Do(func() {fmt.Println("Creating Singleton instance")instance = &Singleton{}})return instance
}func main() {for i := 0; i < 3; i++ {go func() {_ = GetInstance()}()}// 等待所有 goroutine 执行完成fmt.Scanln()
}
输出结果:
Creating Singleton instance
说明:
- 无论
GetInstance()
被调用多少次,Singleton
的实例只会被创建一次。
注意事项
-
sync.Once
的方法只能调用一次,无法重置:- 一旦某个函数通过
Do
被执行,sync.Once
的状态就不可逆转。
- 一旦某个函数通过
-
Do
内部的函数必须确保不会抛出错误:- 如果函数出错,
sync.Once
不会再重新执行它,即使逻辑上需要重试。
- 如果函数出错,
总结
- 功能:
sync.Once
提供了一种线程安全的机制,确保某段代码只执行一次。 - 适用场景:
- 初始化操作:如单例模式、加载配置、初始化全局资源等。
- 性能优化:避免重复执行耗时的操作。
- 优点:高效且线程安全,无需手动加锁控制。