[关闭]
@SovietPower 2023-02-04T20:21:40.000000Z 字数 1646 阅读 707

go sync.Map 测试

项目



测试过程

共5部分,分别对无锁map、操作前获取锁map、sync.Map 进行测试:

注:

测试结果

  1. cpu: Intel(R) Core(TM) i5-8300H CPU @ 2.30GHz
  2. BenchmarkInsertM
  3. BenchmarkInsertM-8 157 7122375 ns/op
  4. BenchmarkInsertL
  5. BenchmarkInsertL-8 157 7528680 ns/op
  6. BenchmarkInsertS
  7. BenchmarkInsertS-8 32 32121606 ns/op
  8. BenchmarkUpdateM
  9. BenchmarkUpdateM-8 372 3227915 ns/op
  10. BenchmarkUpdateL
  11. BenchmarkUpdateL-8 301 3862922 ns/op
  12. BenchmarkUpdateS
  13. BenchmarkUpdateS-8 84 14535339 ns/op
  14. BenchmarkReadM
  15. BenchmarkReadM-8 400 2913653 ns/op
  16. BenchmarkReadL
  17. BenchmarkReadL-8 342 3443182 ns/op
  18. BenchmarkReadS
  19. BenchmarkReadS-8 138 9800634 ns/op
  20. BenchmarkDeleteM
  21. BenchmarkDeleteM-8 780 1524906 ns/op
  22. BenchmarkDeleteL
  23. BenchmarkDeleteL-8 564 2217222 ns/op
  24. BenchmarkDeleteS
  25. BenchmarkDeleteS-8 174 7187940 ns/op
  26. BenchmarkDeleteM2
  27. BenchmarkDeleteM2-8 973 1269203 ns/op
  28. BenchmarkDeleteL2
  29. BenchmarkDeleteL2-8 621 1883041 ns/op
  30. BenchmarkDeleteS2
  31. BenchmarkDeleteS2-8 169 7703778 ns/op

对代码的理论分析:当操作不涉及dirty时(读写的key都在read中),只需要CASread即可,不需要锁,效率高。
但结果总体和理论分析相差很大:

  1. sync.Map 对旧键的更新,相比新键插入和其它map,并没有明显提升。
    无论是新键插入,还是旧键更新,sync.Map 都要慢近5倍。
  2. 是否将 dirty 复制给 read,对性能的影响没有很大(只有小提升)。
  3. map无论是否加锁,效率都比 sync.Map 高很多。在写时差距近5倍,读时差距更小约为3倍。
  4. 因为 sync.Map 不会真正删除元素,只会标记为nilexpunged,直到dirty覆盖read,所以理论上大量删除read后,read这个map中依旧可能有大量元素,多少会影响哈希表的效率(删除测试1)。但实际上,未真正删除的数据影响并不大(删除测试2)。

原因应该是由于环境为单线程,在并行压力大的情况下前两种情况应该都会有较大提升,同时加锁map性能会大幅下降。

总结

sync.Map 适用场景:多线程压力大,读多写少,或程序中操作的键值集合变化不大。
理论上,只要不频繁插入新键,就能基本保持只用CAS而不需要锁。

在第一次新建dirty时,需要拷贝read,可能发生性能抖动。

注意和 Mutex 一样, sync.Map 也同样不能被复制,因为 atomic.Value 是不能被复制的。

测试代码


添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注