OpenMP并行区域omp do内调用含omp do子例程的结果与性能问题咨询
OpenMP嵌套调用规范说明
现有代码的核心问题
你的写法违反了两条OpenMP核心使用规则,直接导致结果错误和运行卡顿:
- 无意义的内层并行开销:主程序的
!$omp parallel已经完成了线程分叉,所有线程并行执行外层omp do分配的(i,j)迭代任务。你在子程序中又加入!$omp do指令,会强制每个外层迭代都要在线程组内再次分配9x9的小循环任务,任务调度开销远大于999=729次浮点计算的开销,直接导致运行速度极慢。 - 数据竞争:子程序中定义的局部数组
tmp默认在并行区域内为共享属性,多个线程同时写入tmp数组会互相覆盖计算结果,自然无法得到正确输出。另外主程序中c、temp、final三个数组未声明为线程私有,多个线程同时修改也会产生数据竞争。
两类嵌套场景的正确写法
场景1:外层循环量足够大(你的场景适用)
当外层循环迭代数远大于CPU物理核心数时,只保留外层并行即可,内层不需要额外加OpenMP指令:
- 删除子程序中的
!$omp do和!$omp enddo指令 - 子程序开头添加
!$omp private(tmp)声明,或者给tmp加上automatic属性,保证每个线程调用子程序时拥有独立的tmp副本 - 主程序外层并行指令修改为
!$omp parallel private(c,temp,final),将每次迭代需要修改的数组声明为线程私有,避免跨线程覆盖
场景2:外层循环量很小、内层计算量极大
如果外层只有个位数迭代,每次迭代需要执行大矩阵乘法(比如1000x1000规模),可以开启嵌套并行:
- 程序初始化阶段调用
omp_set_nested(.true.)主动开启OpenMP嵌套并行支持 - 子程序中的循环指令修改为
!$omp parallel do private(i,j,k,tmp),每次进入子程序时独立开启新的并行区域 - 注意控制嵌套线程总数:外层线程数 * 内层线程数不要超过CPU物理核心数,避免线程超额订阅导致性能下降
你的场景优化建议
你当前外层有(10+1)*(10+1)=121次迭代,远大于普通CPU的核心数,完全不需要内层并行,按场景1修改后即可得到正确结果,且性能达到最优。
内容的提问来源于stack exchange,提问作者Mac cchiatooo
相关产品推荐
相关产品推荐

