如何使用sync.Once确保某个函数只执行一次?
在 Go 语言里,sync.Once
类型能够保证某个函数只执行一次,即便有多个 goroutine
同时调用该函数也是如此。sync.Once
类型具备一个 Do
方法,该方法接收一个无参数无返回值的函数作为参数。下面详细介绍使用 sync.Once
确保函数只执行一次的方法,同时给出示例代码。
基本用法
sync.Once
的基本用法如下:
package main
import (
"fmt"
"sync"
)
// 定义一个 sync.Once 变量
var once sync.Once
// 要确保只执行一次的函数
func initFunction() {
fmt.Println("Initialization function is executed.")
}
func main() {
// 创建多个 goroutine 调用 once.Do
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
once.Do(initFunction)
}()
}
// 等待所有 goroutine 完成
wg.Wait()
}
在上述代码中:
- 定义了一个
sync.Once
类型的变量once
。 - 定义了
initFunction
函数,这是我们要确保只执行一次的函数。 - 在
main
函数里,创建了 5 个goroutine
,每个goroutine
都会调用once.Do(initFunction)
。 once.Do
方法会保证initFunction
仅执行一次。
代码解释
sync.Once
类型内部维持着一个标志位,用来记录函数是否已经执行过。once.Do
方法首先检查标志位,若函数未执行过,就会执行传入的函数,并且将标志位设置为已执行;若函数已经执行过,once.Do
方法会直接返回,不会再次执行该函数。
适用场景
sync.Once
通常用于以下场景:
- 单例模式:保证某个对象只被创建一次。
- 初始化操作:确保某些初始化代码只执行一次,例如加载配置文件、初始化数据库连接等。
下面是一个单例模式的示例:
go
package main
import (
"fmt"
"sync"
)
// Singleton 单例对象
type Singleton struct{}
// 单例实例
var instance *Singleton
// 用于确保单例实例只被创建一次
var once sync.Once
// GetInstance 获取单例实例
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{}
fmt.Println("Singleton instance is created.")
})
return instance
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
_ = GetInstance()
}()
}
wg.Wait()
}
在这个单例模式示例中,once.Do
保证了 Singleton
实例只被创建一次,即便有多个 goroutine
同时调用 GetInstance
方法。