我有一段代码,我只想运行一次以进行初始化。到目前为止,我使用 sync.Mutex 结合 if 子句来测试它是否已经运行。后来我在同一个同步包中遇到了 Once 类型及其 DO() 函数。
实现如下https://golang.org/src/sync/once.go:
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 1 {
return
}
// Slow-path.
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
defer atomic.StoreUint32(&o.done, 1)
f()
}
}
查看代码,它基本上是我之前一直在使用的相同的东西。与 if 子句结合的互斥量。但是,添加的函数调用使我觉得这看起来效率很低。我做了一些测试并尝试了各种版本:
func test1() {
o.Do(func() {
// Do smth
})
wg.Done()
}
func test2() {
m.Lock()
if !b {
func() {
// Do smth
}()
}
b = true
m.Unlock()
wg.Done()
}
func test3() {
if !b {
m.Lock()
if !b {
func() {
// Do smth
}()
b = true
}
m.Unlock()
}
wg.Done()
}
我通过运行以下代码测试了所有版本:
wg.Add(10000)
start = time.Now()
for i := 0; i < 10000; i++ {
go testX()
}
wg.Wait()
end = time.Now()
fmt.Printf("elapsed: %v\n", end.Sub(start).Nanoseconds())
结果如下:
elapsed: 8002700 //test1
elapsed: 5961600 //test2
elapsed: 5646700 //test3
甚至值得使用 Once 类型吗?它很方便,但性能甚至比始终序列化所有例程的 test2 更差。
另外,为什么他们在 if 子句中使用 atomic int?无论如何,存储都发生在锁内。
编辑:Go playground 链接:https://play.golang.org/p/qlMxPYop7kS注意:这不会显示结果,因为 playground 的时间是固定的。
繁星点点滴滴
相关分类