OpenMP:for循环,迭代次数变化

时间:2015-09-22 20:53:22

标签: multithreading for-loop parallel-processing openmp

我想使用OpenMP让我的程序运行得更快。不幸的是,情况正好相反。我的代码看起来像这样:

const int max_iterations = 10000;
int num_interation = std::numeric_limits<int>::max();

#pragma omp parallel for
for(int i = 0; i < std::min(num_interation, max_iterations); i++)
{
  // do sth.

  // update the number of required iterations
  // num_interation can only become smaller over time
  num_interation = update_iterations(...);
}

出于某种原因,处理的迭代次数要多于所需的次数。没有OpenMP,它需要500次迭代才能获得。但是,即使将线程数设置为1(set_num_threads(1)),它也会计算超过一千次迭代。如果我使用mutliple线程,并且在更新num_iterations时使用writelock时也会发生同样的情况。

我认为它有内存带宽或竞争条件的东西。但是在set_num_threads(1)的情况下不应出现这些问题。

因此,我认为它可能与调度和块大小有关。但是,我真的不确定这一点。

有人可以给我一个提示吗?

1 个答案:

答案 0 :(得分:2)

the OpenMP standard第56页

给出了您遇到的行为的快速答案
  

在进入之前计算每个相关循环的迭代计数   到最外面的循环。如果任何相关循环的执行发生任何变化   用于计算任何迭代计数的值,然后是   行为未指明。

实质上,这意味着一旦输入,就无法修改循环的边界。虽然根据标准,行为是&#34;未指定&#34;,在您的情况下,发生的事情非常清楚,因为只要在代码上切换OpenMP,就会计算最初指定的迭代次数。 / p>

所以你必须采取另一种方法解决这个问题。

这是一个可能的解决方案(在许多其他方面),我希望可以扩展。它的缺点是可能允许更多的迭代发生,而不是预期的数量(假设//do sth.是平衡的,假设update_iterations(...)是平衡的,则多达OMP_NUM_THREADS-1次迭代),如果没有,则还有更多迭代。此外,它假设num_interation = std::min(num_interation, max_iterations); #pragma omp parallel { int i = omp_get_thread_num(); const int nbth = omp_get_num_threads(); while ( i < num_interation ) { // do sth. // update the number of required iterations // num_interation can only become smaller over time int new_num_interation = update_iterations(...); #pragma omp critical num_interation = std::min(num_interation, new_num_interation); i += nbth; } } 是线程安全的,并且可以并行调用而没有不必要的副作用...... 这是一个非常强大的假设,您可以更好地执行!

//do sth.

更加同步的解决方案,如果num_interation = std::min(num_interation, max_iterations); int nb_it_done = 0; #pragma omp parallel { int i = omp_get_thread_num(); const int nbth = omp_get_num_threads(); while ( nb_it_done < num_interation ) { // do sth. // update the number of required iterations // num_interation can only become smaller over time int new_num_interation = update_iterations(i); #pragma omp critical num_interation = std::min(num_interation, new_num_interation); i += nbth; #pragma omp single nb_it_done += nbth; } } 没有如此平衡并且没有做太多额外的迭代很重要,可能是:

i

另一个奇怪的事情是,由于你没有显示//do sth.用于什么,因此如果在某种程度上随机迭代进入域是一个问题,则不清楚。如果不是,第一个解决方案应该运行良好,即使对于不平衡的{{1}}也是如此。但如果这是一个问题,那么你最好坚持第二个解决方案(甚至可能加强同步)。

但是在一天结束时,现在有办法(我可以想到并且具有良好的并行性)来避免可能的额外工作,因为迭代次数可能会在此过程中发生变化。