我想知道使用 OpenMP 的 for 循环的进度。我知道减少指令不起作用,但我是这样写的:
#pragma omp for reduction (+:sum)
for (int i=0; i < size; i++){
// do something that takes about 10seconds
sum++;
#pragma omp critical
cout << sum << " / " << size << endl;
}
这将返回如下内容:
1 / 100
1 / 100
2 / 100
1 / 100
...
但我想要这个:
1 / 100
2 / 100
3 / 100
. ..
有没有办法在指令reduction
期间获得正确的sum
值?还是我应该使用其他方法?
reduction
子句具有非常明确定义的含义,在最新 OpenMP 标准的第 2.9.3.6 节中有详细说明。我怀疑您是否能够将其用于上述目的。
无论如何,只需对源代码稍作修改即可实现该行为:
sum = 0
#pragma omp for shared(sum) schedule(guided)
for (int i=0; i < size; i++){
// do something that takes about 10seconds
#pragma omp critical(PRINT)
{
sum++;
cout << sum << " / " << size << endl;
}
}
通过这种方式,您可以确保一次只有一个线程尝试增加"总和"并将其打印在屏幕上。鉴于每次迭代需要很长时间,这种同步不应引起性能问题。
你应该使用另一种方法。缩减会创建一个线程私有变量(在您的情况下sum
),它仅在所有线程加入时结束时减少。减少与实施高度相关。它可以等待所有线程完成,它可以在线程完成时减少,它可以创建一个缩减树,等等。
相反,为了跟踪进度,您可以有另一个变量numDone
,每个线程原子增加。
编辑
维基百科解释得很好:
reduction(operator | ininsic : list):变量有一个本地副本 在每个线程中,但将汇总本地副本的值 (缩减)为全局共享变量。
为了避免通信的需要(通过更新共享计数器),您可以打印出线程编号以及到目前为止已处理的项目数,即
#pragma omp parallel
{
int count = 0;
#pragma omp for schedule(dynamic) // or whatever schedule you want
for(int i=0; i<size; ++i) {
// ...
printf("@ %d: done %d loopsn",
omp_get_thread_num(),++count); // should not need a critical section
}
}
在您的特定情况下,由于工作大约需要 10 秒,因此任何通信都不重要,但使用动态时间表可能是值得的,特别是如果工作在不同i
之间可能有所不同。