sync.Once.Do(f func())是一个挺有趣的东西,能保证once只执行一次,无论你是否更换once.Do(xx)这里的方法,这个sync.Once块只会执行一次 与sync.WaitGroup类型一样,sync.Once类型也属于结构体类型,同样也是开箱即用和并发安全的。由于这 个类型中包含了一个sync.Mutex类型的字段,所以,复制该类型的值也会导致功能的失效。 Once类型的Do方法只接受一个参数,这个参数的类型必须是func(),即:无参数声明和结果声明的函数。 ~~~ package main import ( "fmt" "sync" "time" ) func onces() { fmt.Println("onces") } func onced() { fmt.Println("onced") } var once sync.Once func main() { for i, v := range make([]string, 10) { once.Do(onces) fmt.Println("count: ", v, "---", i) } for i := 0; i < 10; i++ { go func() { once.Do(onced) fmt.Println("213") }() } time.Sleep(4000) } ~~~ 输出 ~~~ onces count: --- 0 count: --- 1 count: --- 2 count: --- 3 count: --- 4 count: --- 5 count: --- 6 count: --- 7 count: --- 8 count: --- 9 213 ~~~ 光会用是不够的,再来看下sync.once的实现原理 源码: ~~~ // Once is an object that will perform exactly one action. type Once struct { m Mutex done uint32 } . . . func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 1 { return } o.m.Lock() defer o.m.Unlock() if o.done == 0 { defer atomic.StoreUint32(&o.done, 1) f() } } ~~~