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

当我比较sync.mu,sync.Map和atomic.Valuego 的效率时,预计它sync.mu的效率低于后两者。但是当我做一个基准测试时,发现使用sync.mu. 所以我想知道原因或者可能有最佳实践。


代码


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


Scene1:在map中改变一个随机的kv对,sync.muvssync.Map

// 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)

Scene2:换一整张图,sync.muvsatomic.Value

// 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


回首忆惘然
浏览 99回答 1
1回答

慕盖茨4494581

你没有比较这种同步结构的效率,因为你也在做 I/0。这段代码中还有 goroutines 和 waitgroups ……不确定我是否理解您应该考虑比较相同上下文中的相似用法。例如,增加一个计数器。您在 sync.Map 中有一个计数器,atomic.Value 并受互斥锁保护。每种方法都各有利弊,但互斥体只处理同步,而其他结构也处理存储。Mutex 应该更快,因为它……不那么复杂。但是,如果您处理比 uint64 更复杂的东西,则 atomic.Value 的开销可能没问题。例如,使用互斥锁你需要一个特定的锁定/解锁顺序,你可能会在没有适当的测试+竞争条件检测器的情况下发现一些问题。而 atomic.Value 会为你处理这个。我从不使用 sync.Map 但我在使用 atomic.Value 的生产中有非常高效的代码 - 我对此没有意见。正确的基准需要更多的技术方法。
打开App,查看更多内容
随时随地看视频慕课网APP