@@ -350,20 +350,62 @@ func BenchmarkNormal(b *testing.B) {
350350 }
351351}
352352
353+ func BenchmarkAtomicParallel (b *testing .B ) {
354+ b.SetParallelism (100 )
355+ b.RunParallel (func (pb *testing.PB ) {
356+ for pb.Next () {
357+ atomic.StoreInt64 (&a, int64 (0 ))
358+ }
359+ })
360+ }
361+
353362```
354363
364+ 结果:
365+
355366``` shell
356- go test -bench=.
357367goos: darwin
358368goarch: amd64
359- BenchmarkAtomic-4 200000000 7.00 ns/op
360- BenchmarkNormal-4 2000000000 0.39 ns/op
369+ BenchmarkAtomic-4 200000000 7.01 ns/op
370+ BenchmarkNormal-4 2000000000 0.63 ns/op
371+ BenchmarkAtomicParallel-4 100000000 15.8 ns/op
361372PASS
362- ok _/Users/xx /test/go/atomic_bench 2.925s
373+ ok _/Users/didi /test/go/atomic_bench 5.051s
363374```
364375
376+ 可见,atomic 耗时比普通赋值操作要高一个数量级,在有竞争的情况下会更加慢。
377+
365378## false sharing / true sharing
366379
380+ true sharing 的概念比较好理解,在对全局变量或局部变量进行多线程修改时,就是一种形式的共享,而且非常字面意思,就是 true sharing。true sharing 带来的明显的问题,例如 RWMutex scales poorly 的官方 issue,即 RWMutex 的 RLock 会对 RWMutex 这个对象的 readerCount 原子加一。本质上就是一种 true sharing。
381+
382+ false sharing 指的是那些意料之外的共享。我们知道 CPU 是以 cacheline 为单位进行内存加载的,L1 的 cache line 大小一般是 64 bytes,如果两个变量,或者两个结构体在内存上相邻,那么在 CPU 加载并修改前一个变量的时候,会把第二个变量也加载到 cache line 中,这时候如果恰好另一个核心在使用第二个变量,那么在 P1 修改掉第一个变量的时候,会把整个 cache line invalidate 掉,这时候 P2 要修改第二个变量的话,就需要再重新加载该 cache line。导致了无谓的加载。
383+
384+ 在 Go 的 runtime 中有不少例子,特别是那些 per-P 的结构,大多都有针对 false sharing 的优化:
385+
386+ runtime/time.go
387+
388+ ``` go
389+ var timers [timersLen]struct {
390+ timersBucket
391+
392+ // The padding should eliminate false sharing
393+ // between timersBucket values.
394+ pad [cpu.CacheLinePadSize - unsafe.Sizeof (timersBucket{})%cpu.CacheLinePadSize ]byte
395+ }
396+ ```
397+
398+ runtime/sema.go
399+
400+ ``` go
401+ var semtable [semTabSize]struct {
402+ root semaRoot
403+ pad [cpu.CacheLinePadSize - unsafe.Sizeof (semaRoot{})]byte
404+ }
405+ ```
406+
407+ 用户态的代码对 false sharing 其实关注的比较少。
408+
367409参考资料:
368410
369411https://homes.cs.washington.edu/~bornholt/post/memory-models.html
0 commit comments