4

我想知道使用 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

. ..

有没有办法在指令sum期间获得正确的值?reduction还是我应该使用另一种方法?

4

3 回答 3

0

你应该使用另一种方法。减少创建一个线程私有变量(在您的情况下sum),它仅在所有线程加入时才减少。减少高度依赖于实现。它可以等待所有线程完成,它可以在线程完成时减少,它可以创建一个减少树,等等。

相反,为了跟踪进度,您可以使用另一个变量numDone,每个线程自动增加该变量。

编辑

维基百科解释得很好:

reduction(operator | intrinsic : list):变量在每个线程中都有一个本地副本,但是本地副本的值将被汇总(缩减)到一个全局共享变量中。

于 2012-09-15T13:36:46.023 回答
0

为了避免需要通信(通过更新共享计数器),您可以打印出线程号以及它到目前为止已处理的项目数,即

#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 loops\n",
           omp_get_thread_num(),++count);   // should not need a critical section
  }
}

在您的特定情况下,由于工作大约需要 10 秒,因此任何通信都不是关键的,但使用动态计划可能是值得的,特别是如果工作可以在不同的i.

于 2012-09-15T17:55:07.767 回答
0

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;     
    }
}

通过这种方式,您可以确保一次只有一个线程试图增加“总和”并将其打印在屏幕上。考虑到每次迭代花费的时间很长,这种同步不应该引起性能问题。

于 2012-09-17T10:41:39.980 回答