sync.Once 源码分析
Once
sync.Once 一般就是用来确保某个动作至多执行一次。
普遍用于初始化资源,单例模式。
type MyBiz struct {
once sync.Once
}
// 只执行一次
func (m *MyBiz) Init() {
m.once.Do(func() {})
}
type singleton struct{}
func (s *singleton) Single() {
fmt.Println("I am single")
}
var inst *singleton
var instOnce sync.Once
func GetSingleInstance() *singleton {
instOnce.Do(func() {
inst = &singleton{}
})
return inst
}
注意 receiver 要使用指针类型,否则每次调用 Close 方法时都会值拷贝,生成一个新的 sync.Once 对象。
type OnceClose struct {
close sync.Once
}
func (o *OnceClose) Close() error {
o.close.Do(func() {
fmt.Println("close")
})
return nil
}
Once 例子
Beego 用 Once 来初始化 Web 模块
initBeforeHTTPRun 可能会在多个地方被调用,所以需要使用 Once
来确保只会执行一次。
从 TODO 标记也可以看出来,在一些情况下,
Once 可能暗示着代码可以放到包初始化方法 init
里面调用。
var initHttpOnce sync.Once
// TODO move to module init function
func initBeforeHTTPRun() {
initHttpOnce.Do(func() {
// init hooks
AddAPPStartHook(
registerMime,
registerDefaultErrorHandler,
registerSession,
registerTemplate,
registerAdmin,
registerGzip,
// registerCommentRouter,
)
for _, hk := range hooks {
if err := hk(); err != nil {
panic(err)
}
}
})
}
Once 重置
sync.Once
没有重置功能,所以可以通过 ponce *sync.Once
并使用 ponce = new(sync.Once)
进行重置。之所以没有设计重置功能,是因为这违背了 sync.Once
的初衷,它的目的是确保操作只执行一次。
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。