为什么OpenMP中线程数增加时矩阵向量乘法耗时反而升高?
问题核心原因
1. rand() 函数线程不安全导致锁竞争
这是耗时异常飙升的最主要原因:
- 标准库的
rand()函数内部维护全局的随机数状态,多线程并发调用时会触发内部锁竞争,大量CPU时间消耗在锁等待上,而非实际计算 - 你的代码前两处
#pragma omp parallel for并行循环里,每轮迭代都调用rand()赋值,线程数从1升到2时,锁竞争直接成为性能瓶颈,出现耗时数倍上涨的情况 - 4、8线程耗时略有好转属于调度器竞争策略的波动,本质还是锁开销远大于计算收益,没有体现出并行计算的优势
2. 额外注意点
clock()函数统计的是进程所有线程的CPU时间总和,多线程场景下数值会是墙钟时间的N倍(N为活跃线程数),你用gettimeofday统计墙钟时间的方式更适合并行程序耗时评估- 当前测试逻辑里随机数生成的开销远大于矩阵向量乘法本身的计算开销,导致你实际测试的是多线程下
rand()的性能,而非矩阵运算的并行加速效果
修复方案
- 提前在单线程环境下生成所有矩阵、向量的随机值,不要把
rand()放在并行循环内:
// 调整matrix函数逻辑,将随机数生成移到并行区外 void matrix(unsigned int n) { float *matrix = (float *)malloc(sizeof(float) * n * n); float *vector = (float *)malloc(sizeof(float) * n); float *result = (float *)malloc(sizeof(float) * n); // 单线程生成随机数,避免并行区锁竞争 for (int row = 0; row < n; row++) { for (int column = 0; column < n; column++) { matrix[row * n + column] = rand(); } } for (int row = 0; row < n; row++) { vector[row] = rand(); result[row] = 0; } // 仅把计算密集的矩阵向量乘法部分并行化 #pragma omp parallel for for (int row = 0; row < n; row++) { for (int column = 0; column < n; column++) { result[row] += matrix[row * n + column] * vector[column]; } } // 补充内存释放避免泄漏 free(matrix); free(vector); free(result); }
- 如果需要在并行区生成随机数,可使用线程私有的随机数状态(如
rand_r(),或OpenMP 5.0提供的内置随机数工具),避免全局锁竞争。
修复后再测试就能看到并行带来的耗时下降效果,2核4线程的设备上2线程应该能获得接近1.8~2倍的加速比。
内容的提问来源于stack exchange,提问作者Jakob Graf
相关产品推荐
相关产品推荐

