我正在编写的计算代码更多地具有以下原理图:
#pragma omp parallel
{
#pragma omp for nowait
// Compute elements of some array A[i] in parallel
#pragma omp single
for (i = 0; i < N; ++i) {
// Do some operation with A[i].
// This time it is important that operations are sequential. e.g.:
result = compute_new_result(result, A[i]);
}
}
计算A[i]
和compute_new_result
都相当昂贵。所以我的想法是并行计算数组元素,如果任何线程获得空闲,它就会开始执行顺序操作。很可能已经计算了起始数组元素,而其他线程仍然是第一个循环。
但是,要使概念有效,我必须做两件事:
使OpenMP以另一种方式拆分循环,即两个线程:线程1计算 A[0]
,A[2]
,A[4]
和线程2:{{ 1}},A[1]
,A[3]
等
提供一些信号系统。我正在考虑一个标志数组,表明已经计算了A[5]
。然后A[i]
应该等待相应的compute_new_result
的标记在继续之前被释放。
如果有任何提示如何实现这两个目标,我会很高兴。我需要这个解决方案可以在Linux,Windows和Mac上移植。我正在用C ++ 11编写整个代码。
<小时/> 修改
我已经找到了第一个问题的答案。看起来向A[i]
指令添加schedule(static,1)
子句就足够了。
但是,我仍然在考虑第二个问题的优雅解决方案......
答案 0 :(得分:1)
如果您不介意使用生成任务的循环替换OpenMP for 工作共享构造,则可以使用OpenMP任务来实现应用程序的两个部分。
在第一个循环中,您将创建(而不是循环块)承担迭代计算负载的任务。然后,第二个循环的每次迭代也成为OpenMP任务。那么重要的部分就是在不同阶段之间同步任务。
为此,您可以使用任务依赖项(使用OpenMP 4.0引入):
#pragma omp task depend(out:A[0])
{ A[0] = a(); }
#pragma omp task depend(in:A[0])
{ b(A[0]); }
确保在任务a完成之前任务b没有运行。
干杯, -Michael
答案 1 :(得分:0)
这可能是一个扩展的评论而不是答案......
所以,你有一个两阶段的计算。在阶段1中,您可以独立计算数组A
中的每个条目。因此,使用OpenMP parallel for
循环并行化是很简单的。但是这里存在一个问题,对线程进行天真的工作分配可能会导致跨线程的(严重?)不平衡负载。
在第2阶段,有一个计算并不那么容易并行,你计划给第一个线程完成第1阶段的分享。
就我个人而言,我将其分为两个阶段。首先,使用parallel for
循环。在第二滴OpenMP中,只有一个顺序代码。通过调整schedule
子句的参数,在阶段1中对负载平衡进行排序;我很想先试试schedule(guided)
。
如果调整时间表无法提供您想要的余额,那么请调查parallel for
替换task
。
不要通过滚动自己的信令技术使第2阶段的代码复杂化。我并不担心复杂情况会让你感到压力,尽管你可能会担心这一点,但除非你在第1阶段理清负荷平衡,否则并发症将无法带来任何好处。当你做完了不需要将phase2放在OpenMP并行区域内。