1

我想并行化这种循环。请注意,每个“calc_block”都使用上一次迭代获得的数据。

for (i=0 ; i<MAX_ITER; i++){

    norma1 = calc_block1();
    norma2 = calc_block2();
    norma3 = calc_block3();
    norma4 = calc_block4();

    norma = norma1+norma2+norma3+norma4;
    ...some calc...
    if(norma<eps)break;
}

我试过这个,但加速非常小~1.2

for (i=0 ; i<MAX_ITER; i++){
  #pragma omp parallel sections{
     #pragma omp section
       norma1 = calc_block1();
     #pragma omp section
       norma2 = calc_block2();
     #pragma omp section
       norma3 = calc_block3();
     #pragma omp section
       norma4 = calc_block4();
  }

  norma = norma1+norma2+norma3+norma4;
    ...some calc...
  if(norma<eps)break;
}

我认为这是因为在循环内使用部分的开销。但我不知道如何解决它......提前谢谢!

4

1 回答 1

3

您可以通过在并行区域内移动整个循环来减少开销。因此,池中用于实现团队的线程只会“唤醒”一次。这有点棘手,需要仔细考虑变量共享类:

#pragma omp parallel private(i,...) num_threads(4)
{
   for (i = 0; i < MAX_ITER; i++)
   {
      #pragma omp sections
      {
         #pragma omp section
         norma1 = calc_block1();
         #pragma omp section
         norma2 = calc_block2();
         #pragma omp section
         norma3 = calc_block3();
         #pragma omp section
         norma4 = calc_block4();
      }

      #pragma omp single
      {
         norma = norm1 + norm2 + norm3 + norm4;
         // ... some calc ..
      }

      if (norma < eps) break;
   }
}

sections和构造在它们的末端都有single隐含的障碍,因此线程会在进入下一个循环迭代之前同步。该single构造复制了程序的先前串行部分。子句中的...部分private应列出尽可能多的仅与 相关的变量... some calc ...。这个想法是使用线程局部变量运行串行部分,因为大多数 OpenMP 实现对共享变量的访问速度较慢。

请注意,由于完全不同的原因,通常加速可能不是线性的。例如calc_blockX()(with Xbeing 1, 2, 3or 4) 的计算强度可能太低,因此需要非常高的内存带宽。如果内存子系统不能同时提供所有 4 个线程,则加速将小于 4。这种情况的一个例子 -这个问题

于 2013-10-29T18:44:26.477 回答