`sync.Mutex`、`sync.Map` 和 `atomic.Value` 中的效率比较

Efficiency comparation in `sync.Mutex`, `sync.Map`, and `atomic.Value`

当我在go中比较sync.musync.Mapatomic.Value的效率时,预计sync.mu比后两者效率低。但是当我做一个基准测试时,发现使用 sync.mu 执行时间更少。所以我想知道原因或者可能有最佳实践。

代码

源代码在这里https://go.dev/play/p/WODF8Tyyw4d简化如下:

// sync.mu reader
mu.Lock()
tmp := tA[idx]
mu.Unlock()
// sync.mu writer
mu.Lock()
tA[idx] = data
mu.Unlock()

// sync.Map reader
v, _ := tB.Load(idx)
// sync.Map writer
tB.Store(idx, data)
// sync.mu reader
mu.Lock()
tmp := tA[0]
mu.Unlock()
// sync.mu Writer
mu.Lock()
tA = data
mu.Unlock()

// atomic.Value reader
v := tC.Load().(map[int]int)[0]
// atomic.Value writer
tC.Store(data)

结果

goos: darwin
goarch: amd64
pkg: sync-demo
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkMu-12          1000000000               0.5401 ns/op
BenchmarkSyncMap-12     1000000000               0.5504 ns/op
BenchmarkMuTotal-12     1000000000               0.5418 ns/op
BenchmarkAtomic-12      1000000000               0.5457 ns/op
PASS
ok      sync-demo    64.195s

你不是在比较这种同步结构的效率,因为你也在做 I/0。这段代码中还有 goroutines 和 waitgroups …不知道我是否理解

您应该考虑比较相同上下文中的相似用法。

例如,增加一个计数器。您在 sync.Map、atomic.Value 中有一个计数器并受互斥锁保护。

每种方法各有利弊,但互斥体只处理同步,而其他结构也处理存储。

Mutex 应该更快,因为它……不那么复杂。

但是,如果您处理的东西比 uint64 更复杂,那么 atomic.Value 的开销可能没问题。

例如,使用互斥锁需要特定的 lock/unlock 顺序,如果没有适当的测试 + 竞争条件检测器,您可能会发现一些问题。

虽然 atomic.Value 为您处理。

我从不使用 sync.Map 但我在生产中使用 atomic.Value 的代码非常高效 - 我对此没有意见。

正确的基准需要更多的技术方法。