我想使用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)的情况下不应出现这些问题。
因此,我认为它可能与调度和块大小有关。但是,我真的不确定这一点。
有人可以给我一个提示吗?
答案 0 :(得分:2)
在进入之前计算每个相关循环的迭代计数 到最外面的循环。如果任何相关循环的执行发生任何变化 用于计算任何迭代计数的值,然后是 行为未指明。
实质上,这意味着一旦输入,就无法修改循环的边界。虽然根据标准,行为是&#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}}也是如此。但如果这是一个问题,那么你最好坚持第二个解决方案(甚至可能加强同步)。
但是在一天结束时,现在有办法(我可以想到并且具有良好的并行性)来避免可能的额外工作,因为迭代次数可能会在此过程中发生变化。