交替调整OpenMP并行线程数时Visual Studio 2019出现严重性能损失
根本原因:MSVC 默认OpenMP运行时的线程池实现缺陷
- Visual Studio 2019 默认搭载的OpenMP运行时仅支持OpenMP 2.0标准,其内部线程池逻辑非常僵化:当新的并行区域请求的线程数与当前已创建的工作线程数量不匹配时,会直接销毁整个现有线程池,再重新创建对应数量的全新工作线程,线程销毁、创建的系统开销极高。
- 你的第二轮测试场景中,每次调用
foo函数时,两个连续的parallel for分别使用j和j+1个线程,每进入一个新的并行区域就会触发一次全量线程销毁+重建的操作,而每个测试用例要循环执行上百次foo,累加的线程管理开销已经远远超过并行计算本身的开销,最终出现几十到上百倍的性能损失。 - 第一轮测试两次并行区域使用相同线程数,仅第一次进入并行区域时创建一次线程池,后续都可以复用现有线程,因此性能表现符合预期。
- 而Ubuntu下GCC使用的
libgompOpenMP运行时实现了弹性线程池逻辑:会维护一个最大数量的工作线程池,当并行区域需要的线程数小于池大小时,多余线程会进入休眠状态等待复用,不会被销毁;需要更多线程时仅新增不足的部分,不会全量重建,因此频繁调整线程数的额外开销极低,两个批次性能表现接近。
可选修复方案
如果需要在MSVC环境下避免该问题,可选择以下两种方案:
- 代码层面尽量避免在运行时频繁切换并行区域的线程数
- 升级到Visual Studio 2022及以上版本,编译时添加
/openmp:llvm开关启用新的基于LLVM的OpenMP运行时,该版本已经修复了线程池频繁销毁重建的问题。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

