once是什么
和singlefight有些相似,singlefight是并发执行时只有一个在执行, once也是并发时只有一个在执行,只不过,只执行一次,再次调用不会在执行
once怎么用
var A int
var once = sync.Once{}
func initA() int {
once.Do(func() { //这里只会执行一次
A = 10 //A=10 只会执行一次,并且所有并发进来的,都需要等待A=10 完成后返回
})
return A // A=10 happens before 读取A, 所以initA()在所有gorutine里,都返回10
}
这个例子我们可以构造一个懒汉模式
单例
源码阅读
Once结构
type Once struct {
done uint32
m Mutex
}
Once结构很简单,只有两个字段, done来表示是否执行完成, m为互斥锁
Do函数
func (o *Once) Do(f func()) {
//判断done 如果没完成,则执行doSlow函数,否则直接返回退出函数
if atomic.LoadUint32(&o.done) == 0 {
o.doSlow(f)
}
}
doSlow (第一次并发执行时才会进入的分支)
func (o *Once) doSlow(f func()) {
o.m.Lock()
defer o.m.Unlock() //上锁
if o.done == 0 {
defer atomic.StoreUint32(&o.done, 1) //完成标志设置为1
f() //执行传入的函数
}
}