Last updated 1 year ago
Go 语言标准库中 可以保证在 Go 程序运行期间的某段代码只会执行一次。
其原理也很简单:用一个数字表示是否执行过 + 锁保证并发场景下只执行一次。后续再次执行时,检查该变量即可。
在使用该结构体时,我们也需要注意以下的问题:
方法中传入的函数只会被执行一次,哪怕函数中发生了 panic
panic
两次调用 方法传入不同的函数只会执行第一次调传入的函数
sync.Once.Do
sync.Once
type Once struct { done uint32 // 用来标识代码块是否执行过 m Mutex // 互斥锁 } func (o *Once) Do(f func()) { // done==0,说明没执行过,进入慢路径 if atomic.LoadUint32(&o.done) == 0 { o.doSlow(f) } } func (o *Once) doSlow(f func()) { o.m.Lock() defer o.m.Unlock() if o.done == 0 { // 双重检查。因为可能有多个协程进入慢路径。第一个协程执行完毕后,后面的协程按顺序还能获取锁,此时再判断一次 defer atomic.StoreUint32(&o.done, 1) // 执行成功后将 done 变量修改为1 f() } }