【问题标题】:Parallelizing for loop with openMP inside of while loop?在while循环内使用openMP并行化for循环?
【发布时间】:2019-01-07 18:23:41
【问题描述】:

我有一个类似这样的程序结构:

ssize_t remain = nsamp;
while (!nsamp || remain > 0) { 
    #pragma omp parallel for num_threads(nthread)  
    for (ssize_t ii=0; ii < nthread; ii++) {
        <generate noise>       
    } 

    // write noise
    out.write(data, nthread*PERITER);
    remain -= nthread*PERITER;
 }

问题是,当我对其输出进行基准测试时,如果我使用例如:两个线程运行,有时它需要与单个线程相同的时间,有时我会获得 2 倍的加速,感觉就像有某种在我遇到的同步竞争条件中,有时我遇到了它并且事情进展顺利,有时(通常)不是。

有谁知道可能导致这种情况的原因以及在外部 while 循环内并行化一个部分的正确方法是什么?

编辑:使用 strace,我看到 很多 对 sched_yield() 的调用良好的调度模式。

【问题讨论】:

  • 总是尝试并行化最外层的循环。看来while 循环和for 循环可以合并为一个循环,然后应该并行化。
  • 你认为它们可以如何结合?
  • 我不明白while循环中!nsamp这个条件是什么意思。
  • 如果我指定 nsamp == 0 我希望它永远循环,直到我 ctrl-c 它
  • 看来产生的数据总量是nsamp,所以一个循环就可以了。如果你想要一个无限循环,无论如何你都应该使用不同的方法。

标签: c++ openmp


【解决方案1】:

每次进入while 循环时,您都会创建一组新线程。在并行循环之后,线程被销毁。由于while 循环的性质,这可能会不规则地发生(取决于条件)。 因此,如果您的循环只执行了几次,那么线程创建过程可能会超过实际工作负载,因此您最多只能获得顺序性能,如果不是更少的话。但是,也许并行系统(OpenMP)可以检测是否多次进入循环以保持线程处于活动状态。

但没有任何保证。

【讨论】:

  • 有什么方法可以告诉 openMP 我要重复执行一个并行区域?
  • 恐怕不行。请注意,在您的 for 循环中可能有其他原因导致此问题,我的回答更像是一个疯狂的猜测。如果您可以将外部循环重写为 for 循环,这可能会有所帮助。这可能使优化编译器能够交换循环或执行其他魔法以使其在大多数情况下更快。
  • 不幸的是,它可能会无限循环,所以我无法真正替换外部循环,我已经更新了代码示例以更好地展示这一点。
  • 我明白了。哎呀,这似乎不太好,恐怕你在这里做不了太多。建议 1:在几个 while 循环条件下按顺序和并行测量您的“噪声产生时间”并绘制图表。如果这暗示在您的应用程序中产生的噪声影响不大,那么请在此处跳过并行性。如果建议 1 失败,您可以尝试搜索实现 Loopo 的编译器,该编译器能够自动并行化 一些 while 循环。
  • @ThomasLang 在 omp parallel 区域内设置 while 循环并在此循环内设置 omp for 有什么问题?
【解决方案2】:

我会建议这样的事情。 对于 nsamp == 0 你需要一些更合理的处理。有关使用 OpenMP 正确处理信号,请参阅this answer

ssize_t remain = nsamp;
#pragma omp parallel num_threads(nthread) shared(out, remain, data)
while (remain > 0) { 
    #pragma omp for
    for (ssize_t ii=0; ii < nthread; ii++) {
        /* generate noise */
    }
    #pragma omp single
    {
        // write noise
        out.write(data, nthread*PERITER);
        remain -= nthread*PERITER;
    }
}

【讨论】:

  • @SeanMcAllister 很抱歉与 cmets 混淆。此代码中必须有 2 个屏障(一个在 for 之后,另一个在 single 之后)。可能您的代码太快了,或者您可能没有正确启用 OpenMP(以防万一)。您也可以尝试为omp for pragma 启用某种调度,而不是利用omp parallel 中的所有nthreads(先尝试删除num_threads(nthread))。
猜你喜欢
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多