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

时间:2016-06-06 01:56:30

标签: c openmp

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

我的主要问题是为什么这两个版本的运行时间相似?不是第二个版本的fork线程只有一次,并且避免了在第一个版本中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);

使用此输出和运行时:

OMP_NUM_THREADS = 1

final=1000
real    0m5.847s
user    0m5.628s
sys     0m0.212s

OMP_NUM_THREADS = 4

final=1000
real    0m4.017s
user    0m15.612s
sys     0m0.336s

第二个版本的代码在外部循环之前启动一次线程(?)并像这样并行化内部循环:

#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_THREADS = 1

final=1000
real    0m5.476s
user    0m4.964s
sys     0m0.504s

OMP_NUM_THREADS = 4

final=1000
real    0m4.347s
user    0m15.984s
sys     0m1.204s

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

2 个答案:

答案 0 :(得分:1)

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

例如,请参阅thread pooling in the Sun Studio OpenMP implementation的解释。

答案 1 :(得分:0)

您似乎正在回顾Amdahl's Law的步骤:它说的是并行进程与其自身的开销。 Amadhl发现的一件事是,无论你在程序中加入多少并行性,它始终都要以相同的加速速度开始。当程序需要足够的工作来补偿额外的处理能力时,并行性才开始改善运行时间/性能。