为何教程中的C++多线程求和示例运行慢于单线程?
多线程计算奇偶和反而比单线程慢的原因分析
我跟着教程写了一段C++代码,用来计算0到1900000000范围内的奇数和与偶数和。单线程版本跑3秒,但多线程版本居然要18秒——我用的是多核CPU,完全搞不懂为什么会这样,明明预期多线程更快才对。
代码如下:
#include <iostream> #include <thread> #include <chrono> #include <algorithm> unsigned long long OddSum = 0; unsigned long long EvenSum = 0; void findEven(unsigned long long start, unsigned long long end){ for (unsigned long long i = start; i <= end; i++){ if((i & 1)==0){ EvenSum += i; } } } void findOdd(unsigned long long start, unsigned long long end){ for (unsigned long long i = start; i <= end; i++){ if((i & 1)==1){ OddSum += i; } } } int main(){ unsigned long long start = 0, end = 1900000000; auto startTime = std::chrono::high_resolution_clock::now(); std::thread t1(findEven, start, end); std::thread t2(findOdd, start, end); t1.join(); t2.join(); // findOdd(start, end); // findEven(start, end); auto stopTime = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stopTime - startTime); std::cout << "OddSum : " << OddSum << std::endl; std::cout << "EvenSum : " << EvenSum << std::endl; std::cout << "Sec : " << duration.count()/1000000 << std::endl; return 0; }
问题根源
- 伪共享(缓存行竞争):全局变量
OddSum和EvenSum大概率被分配到同一个CPU缓存行(通常64字节)。两个线程分别对这两个变量做累加时,每次写入都会让整个缓存行失效,CPU核心之间得不断同步缓存数据,这带来的开销远大于多线程并行的收益。 - 重复遍历导致工作量翻倍:单线程是遍历一次区间同时计算奇偶和,而多线程版本是两个线程各自完整遍历一遍整个范围,总工作量直接翻了一倍,再加上缓存竞争的拖累,速度自然暴跌。
优化方案
- 解决伪共享:让两个全局变量各自独占一个缓存行,比如用C++11的
alignas属性:
alignas(64) unsigned long long OddSum = 0; alignas(64) unsigned long long EvenSum = 0;
或者用GCC编译器的特定属性:
unsigned long long OddSum __attribute__((aligned(64))) = 0; unsigned long long EvenSum __attribute__((aligned(64))) = 0;
拆分任务区间:不要让两个线程重复遍历,而是把区间拆分成两部分,比如一个线程处理0949999999,另一个处理9500000001900000000,每个线程同时计算自己区间内的奇偶和,最后汇总结果。这样既减少了总遍历次数,也避免了缓存竞争。
用数学公式直接计算(最优解):奇偶和完全可以用等差数列公式直接算出,根本不需要循环:
- 偶数和:0到N的偶数构成首项0、末项为
N - (N%2)、公差2的等差数列,项数是(末项/2)+1,和为(0 + 末项) * 项数 / 2 - 奇数和:1到N的奇数构成首项1、末项为
N - (1 - N%2)、公差2的等差数列,项数是(末项 + 1)/2,和为项数 * 项数(因为1+3+5+...+(2k-1)=k²)
这种方法耗时几乎可以忽略,比任何循环版本都高效。
内容的提问来源于stack exchange,提问作者bevenstee
相关产品推荐
相关产品推荐

