两段近似的C++多线程代码运行耗时差异巨大的原因探究
问题原因分析
两段代码的性能差异核心在于**伪共享(False Sharing)**以及全局变量的内存访问冲突:
第一段代码的性能瓶颈
第一段中,evenSum和oddSum是全局变量,在内存中会被连续分配(全局变量存放在数据段,地址连续)。由于unsigned long long占8字节,而CPU缓存行通常为64字节,这两个变量必然处于同一个缓存行中。
当两个线程分别对这两个变量进行写入操作时,CPU的缓存一致性协议(如MESI)会触发频繁的缓存行失效与同步:
- 线程修改
evenSum时,会标记对应缓存行为"已修改",其他CPU核心中对应的缓存行会被置为"无效" - 另一个线程修改
oddSum时,发现自己的缓存行已无效,必须等待对方的缓存行同步回主存后重新加载,反之亦然
这种循环往复的缓存同步导致两个线程无法真正并行执行,而是在互相等待缓存更新,最终性能和单线程几乎无异。
第二段代码的优化逻辑
第二段代码中,每个线程先将全局变量的值读取到线程私有局部变量(函数内的evenSum和oddSum是栈上变量,属于线程私有内存),循环中仅对局部变量进行写入操作。
局部变量会被加载到各自CPU核心的独立缓存行中,互相之间不会产生缓存冲突:
- 两个线程的缓存操作完全独立,不会触发缓存一致性同步
- 线程可以真正并行执行循环计算,因此耗时接近第一段的一半,达到多线程并行的预期效果
由于你未开启编译优化,编译器不会自动将全局变量的访问优化为局部变量访问,因此这种手动修改的性能提升效果会非常明显。
内容的提问来源于stack exchange,提问作者programmer of c
相关产品推荐
相关产品推荐

