如何编写在 C++ openmp 上重用线程的代码?
Posted
技术标签:
【中文标题】如何编写在 C++ openmp 上重用线程的代码?【英文标题】:How can I write codes that reuse thread on C++ openmp? 【发布时间】:2018-05-03 16:17:01 【问题描述】:我有一个函数f,我可以使用并行处理。为此,我使用了 openmp。 但是这个函数被调用了很多次,而且好像每次调用都会创建线程。
我们如何重用线程?
void f(X &src, Y &dest)
... // do processing based on "src"
#pragma omp parallel for
for (...)
...// put output into "dest"
int main()
...
for(...) // It is impossible to make this loop processing parallel one.
f(...);
...
return 0;
【问题讨论】:
使用线程池。 我怎样才能在这段代码上做到这一点? 这是一个相当广泛的问题。在 general 中,您会预先创建多个线程,然后在可用时将工作分配给它们(并且池中有可用线程,否则您会将工作排队)。当一个线程完成其工作时,它会回到池中并等待分配更多工作。 非常感谢。您的建议是在这里使用 openmp 是不好的解决方案。对吗? 具有重复并行计算的使用模型非常适合 OpenMP,并且在实践中很常见。 【参考方案1】:OpenMP 在内部实现线程池,它会尝试重用线程,除非您更改其中的某些设置或使用不同的应用程序线程来调用并行区域,而其他线程仍处于活动状态。
可以通过使用线程局部变量来验证线程确实相同。我建议您验证有关重新创建线程的声明。 OpenMP 运行时除了明显的线程池想法之外还做了很多智能优化,您只需要知道如何正确调整和控制它。
虽然不太可能重新创建线程,但是当您再次调用并行区域时,很容易看出线程是如何进入休眠状态的,并且唤醒它们需要相当长的时间。您可以使用 OMP_WAIT_POLICY=active
和/或特定于实现的环境变量,如 KMP_BLOCKTIME=infinite
(用于 Intel/LLVM 运行时)来防止线程进入休眠状态。
【讨论】:
在this question 中,我在一个循环中实现了并行区域,后来我发现如果我将并行区域移到外循环,性能会好一些。我想知道我是否尝试过OMP_WAIT_POLICY=active
,如果性能会相同。【参考方案2】:
这只是安东正确答案的补充。如果您真的关心这个问题,对于大多数程序,您可以轻松地将并行区域移到外部并保持串行工作串行,如下所示:
void f(X &src, Y &dest)
// You can also do simple computations
// without side effects outside of the single section
#pragma omp single
... // do processing based on "src"
#pragma omp for // note parallel is missing
for (...)
#pragma omp critical
...// each thread puts its own part of the output into "dest"
int main()
...
// make sure to declare loop variable locally or explicitly private
#pragma omp parallel
for(type variable;...;...)
f(...);
...
return 0;
仅当您已测量证据表明您正遭受重新打开并行区域的开销时才使用此选项。您可能需要处理共享变量,或者手动内联 f
,因为在 f
中声明的所有变量都是私有的 - 所以它的详细外观取决于您的特定应用程序。
【讨论】:
我想知道OMP_WAIT_POLICY=active
是否需要这种技术。
@Zboson OMP_WAIT_POLICY
有点正交,应该会影响“手动线程池”。由于该标准没有讨论线程池,因此未使用的线程(与当前线程中的等待线程相反)是否受到等待策略的影响当然取决于实现。无论如何-如有疑问,请测量:-)。在 gcc 7.3.1 的一些测试中,在一些配置中手动方法,在一些简单的方法中稍微快一些。以上是关于如何编写在 C++ openmp 上重用线程的代码?的主要内容,如果未能解决你的问题,请参考以下文章