多线程编程之消除【伪共享】
调试多线程代码,性能一直上不去,今天使用 pipe 性能差的出奇,想要找一份现成的环形队列(一读多写)来代替,结果有了大收获。
多线程下的面向cache优化
之前调性能的思路,基本和 《论程序底层优化的一些方法与技巧》 指出的一样:
总结起来,对于CPU缓存类型的优化,我们编写代码的大体原则就是:本来就有关联的东西(变量、代码),尽量在代码组织上让它们紧密地联系起来。本来毫无关联的东西,就应该把它们相分隔开。这不单单是可以让我们的代码更加有效率,同样也是编写更优美的代码的基本原则。
然而同样是面向cache做优化,多线程优化的关注点却不一样,特别关注消除【伪共享】。
以线程安全的环形队列为例,其数据结构包括一个指针,两个索引 in 和 out。如果这三个数据紧密排列,放在同一个缓存行的话,一个线程修改了 in 或者 out,其他线程即使不需要操作这个成员,L1 缓存也会失效,导致性能下降。然而这三个数据其实本身是独立修改的,不应该互相影响。解决办法也很简单,重新排列数据结构,或者直接加padding,保证不在一个 cacheline(64B)里就可以了,比如 jdk1.8加入的新注解@Contended就可以自动做到这一点。
参考
论程序底层优化的一些方法与技巧 | 成都七中 骆可强
一种极致性能的缓冲队列 | 捉虫大师
高性能队列——Disruptor | 美团技术团队