C++向量求和场景下并行代码运行速度慢于串行代码问题咨询
性能劣化原因
- 核心问题是锁粒度过细导致完全失去并行收益:你的代码里每累加一个向量元素就执行一次
Mutex.lock()/Mutex.unlock(),1000万次的加解锁本身就有极高的开销,且互斥锁保证同一时间只有一个线程能修改全局Sum变量,相当于所有线程的计算过程实际是串行执行的,8线程场景下还额外增加了大量锁竞争、线程上下文切换的成本,因此耗时远高于单线程版本。 - 额外固定开销:线程创建、调度本身也有固定成本,在你的实现里并行收益完全为负的情况下,这些成本会进一步拉高耗时。
优化方案
最优解法是取消全局累加的互斥锁,改为线程局部求和后统一合并,每个线程仅计算自己负责分片的和,存在局部变量中,所有线程执行完毕后主线程再把所有分片的和加总即可,全程无锁竞争,能充分利用多核性能。
优化后参考代码
#include <iostream> #include <vector> #include <thread> #include <chrono> #include <cmath> using namespace std; /* 并行求和函数:返回当前分片的求和结果 */ double Function_Sum(const vector<double>& Vector, unsigned int kin, unsigned int kend) { double local_sum = 0; for(unsigned int k = kin; k <= kend; ++k) { // 无锁,仅操作线程局部变量,无竞争 local_sum += Vector[k]; } return local_sum; } int main(int argc, char *argv[]) { unsigned int ThreadsSize = 8; vector<thread> Threads; // 存储每个线程的局部求和结果 vector<double> thread_sums(ThreadsSize, 0); vector<double> Vector(10000000,1); unsigned int kin, kend; unsigned int dk = floor(Vector.size() / ThreadsSize); cout << "VectorSize = " << Vector.size() << ", ThreadsSize = " << ThreadsSize << ", dk = " << dk << endl; auto t_start = std::chrono::high_resolution_clock::now(); for(unsigned int k = 0; k < ThreadsSize; ++k) { kin = k * dk; kend = (k + 1) * dk - 1; if(k == ThreadsSize - 1) { kend = Vector.size() - 1; } cout << k << " in: " << kin << ", end: " << kend << endl; // 把对应位置的引用传给线程,存局部求和结果 Threads.emplace_back([&, k, kin, kend](){ thread_sums[k] = Function_Sum(Vector, kin, kend); }); } for(auto& t : Threads) { t.join(); } // 合并所有线程的结果 double Sum = 0; for(auto s : thread_sums) Sum += s; auto t_end = std::chrono::high_resolution_clock::now(); double elapsed_time_ms = std::chrono::duration<double, std::milli>(t_end-t_start).count(); cout << "Sum = " << Sum << endl; cout << "Time = " << elapsed_time_ms << endl; return 0; }
优化后8线程耗时会接近单线程的1/8,符合预期。
内容的提问来源于stack exchange,提问作者FGP92
相关产品推荐
相关产品推荐

