理解 CPU Cache 对并发性能的影响

目录

一般来说每个 CPU 核有 L1 和 L2 缓存,L3是共享缓存 以缓存行为单位存储,通常是 64 字节为一行

这种利用局部性原理的缓存是数组访问比链表访问快的主要原因

伪共享问题 false sharing

如果两个核都有同一个缓存行,但是它们操作的却是缓存行中的不同变量,这时就会出现伪共享问题,处理器会用标志标记缓存行的修改状态,需要通过 MESI 协议通信来传输被修改的缓存行。表面上看这两个变量是在不同的 L1 中被独立修改的,但事实上它们都共享 L3 上的同一个缓存行,其中会存在大量的数据同步的通信开销

通信获取缓存的先决条件:

  • 线程的工作从一个核换到另一个核(联系GPM模型中的被绑定的M,这也是为什么最好是由原来绑定的M来运行G的重要原因,利用处理器局部缓存!)
  • 两个不同的核需要处理相同的缓存行

解决伪共享问题

案例:当多个线程需要处理多个相邻的数据项的时候? 如:并发地修改数组,结构体里相邻的字段存在被并发读取修改的情况等

其中一个可行的办法就是进行边界填充,在 Go 中通常情况下可以使用匿名下划线的 []byte 进行填充,让这些受影响的数据项位于不同的 cache line 即可,这样就能够打破共享从而避免数据同步通信的开销