C 如何避免嵌套循环中openMP的开销

C 如何避免嵌套循环中openMP的开销,c,openmp,C,Openmp,我有两个版本的代码,它们会产生相同的结果,我尝试只对嵌套的for循环的内部循环进行并行化。我没有得到太多的加速,但我没想到会有1对1的加速,因为我只是尝试并行化内部循环 我的主要问题是为什么这两个版本有相似的运行时?第二个版本不是只有一次分叉线程,并且避免了像第一个版本那样在i上每次迭代时启动新线程的开销吗 代码的第一个版本在外部循环的每次迭代中启动线程,如下所示: for(i=0; i<2000000; i++){ sum = 0; #pragma omp parallel fo

我有两个版本的代码,它们会产生相同的结果,我尝试只对嵌套的
for
循环的内部循环进行并行化。我没有得到太多的加速,但我没想到会有1对1的加速,因为我只是尝试并行化内部循环

我的主要问题是为什么这两个版本有相似的运行时?第二个版本不是只有一次分叉线程,并且避免了像第一个版本那样在
i
上每次迭代时启动新线程的开销吗

代码的第一个版本在外部循环的每次迭代中启动线程,如下所示:

for(i=0; i<2000000; i++){
  sum = 0;
  #pragma omp parallel for private(j) reduction(+:sum)
  for(j=0; j<1000; j++){
    sum += 1;
  }
  final += sum;
}
printf("final=%d\n",final/2000000);
#pragma omp parallel private(i,j)
for(i=0; i<2000000; i++){
  sum = 0;
  #pragma omp barrier
  #pragma omp for reduction(+:sum)
  for(j=0; j<1000; j++){
    sum += 1;
  }
  #pragma omp single
  final += sum;
}
printf("final=%d\n",final/2000000);
OMP_NUM_线程数=4

final=1000
real    0m4.017s
user    0m15.612s
sys     0m0.336s
final=1000
real    0m4.347s
user    0m15.984s
sys     0m1.204s
第二个版本的代码在外循环之前启动一次线程(?),并将内循环并行化,如下所示:

for(i=0; i<2000000; i++){
  sum = 0;
  #pragma omp parallel for private(j) reduction(+:sum)
  for(j=0; j<1000; j++){
    sum += 1;
  }
  final += sum;
}
printf("final=%d\n",final/2000000);
#pragma omp parallel private(i,j)
for(i=0; i<2000000; i++){
  sum = 0;
  #pragma omp barrier
  #pragma omp for reduction(+:sum)
  for(j=0; j<1000; j++){
    sum += 1;
  }
  #pragma omp single
  final += sum;
}
printf("final=%d\n",final/2000000);
OMP_NUM_线程数=4

final=1000
real    0m4.017s
user    0m15.612s
sys     0m0.336s
final=1000
real    0m4.347s
user    0m15.984s
sys     0m1.204s

为什么第二个版本没有比第一个快很多?它不是避免了每次循环迭代时启动线程的开销,还是我做错了什么?

OpenMP实现可以使用线程池来消除遇到并行构造时启动线程的开销。为第一个并行构造启动一个
OMP\u NUM\u线程池
THREADS,构造完成后,从线程返回池。当遇到以后的并行构造时,可以重新分配这些空闲线程


例如,请参见此解释。

您似乎在追溯以下步骤:它谈到并行处理与自身开销。Amadhl发现的一件事是,无论您在程序中投入了多少并行性,它都必须从相同的加速开始。只有当程序需要足够的工作来补偿额外的处理能力时,并行性才开始改善运行时/性能。

可能是因为OpenMP的实现有效地将第一个版本转换为第二个版本。大多数实现都足够聪明,如果它看到线程不断在外部循环中创建,就可以让线程保持活动状态。即使有线程池,你的第二个版本也会更好。哦,我很惊讶你的第二个版本速度较慢。你用优化编译了吗?我试过优化你的代码,没有OpenMP,内部循环优化到1000,但是OpenMP没有。您可能没有使用优化进行编译。此外,我高度怀疑第一个版本会转换为第二个版本,即使使用优化。OpenMP实现使用线程池,因此在许多情况下,您可能不会发现两者之间的差异,但这并不意味着它们是相等的。很好的一点。下次测试时,我将运行一个更现实的案例并使用优化。我的实际问题更像是一个随机行走,外循环是一个时间步,内循环是我想要并行化的一群行走者。最后,我把我的代码转换成了MPI,它的速度是进程数的几倍,所以我很满意。@nick,出于兴趣,你用的是什么C编译器/OpenMP实现?