#pragma omp parallel for ordered
for (int i = 0; i < n; ++i) {
... code happens nicely in parallel here ...
#pragma omp ordered
{
.. one at a time in order of i, as expected, good ...
}
... single threaded here but I expected parallel ...
}
我希望下一个线程在该线程离开有序部分后立即进入有序部分。但是当for循环的主体结束时,下一个线程只进入有序部分。因此,有序部分结束后的代码顺序进行。
OpenMP 4.0手册包含:
有序构造指定循环区域中的结构化块 这将按循环迭代的顺序执行。这个 在有序区域内对代码进行顺序化和排序 允许代码在区域外并行运行。
我添加了粗体。在有序部分结束后,我正在“外部”阅读。
这是预期的吗?订购的部分实际上必须是最后一个吗?
我已经找到了一个答案,并找到了另一个地方近2年前有人观察到类似的地方:https://stackoverflow.com/a/32078625/403310:
使用gfortran 5.2进行测试后,它会在订购后出现 为了每个循环迭代执行一个区域,所以有了 循环开始时的有序块导致串行性能 虽然在循环结束时有序块但没有 这意味着块之前的代码是并行化的。测试 与ifort 15并不那么戏剧化,但我仍然会推荐 构造您的代码,以便在任何代码之后发生您的有序块 需要在循环迭代中而不是之前进行并行化。
我在Ubuntu 16.04上使用gcc 5.4.0。
非常感谢。
答案 0 :(得分:6)
ordered
区域不需要最后。您观察到的行为是依赖于实现的,以及libgomp
(来自gcc的OpenMP运行时库)中的已知缺陷。我认为标准可以容忍这种行为,但显然不是最佳的。
从技术上讲,编译器会从注释中生成以下代码:
#pragma omp parallel for ordered
for (int i = 0; i < n; ++i) {
... code happens nicely in parallel here ...
GOMP_ordered_start();
{
.. one at a time in order of i, as expected, good ...
}
GOMP_ordered_end();
... single threaded here but I expected parallel ...
GOMP_loop_ordered_static_next();
}
不幸的是,GOMP_ordered_end
是implemented as follows:
/* This function is called by user code when encountering the end of an
ORDERED block. With the current ORDERED implementation there's nothing
for us to do.
However, the current implementation has a flaw in that it does not allow
the next thread into the ORDERED section immediately after the current
thread exits the ORDERED section in its last iteration. The existance
of this function allows the implementation to change. */
void
GOMP_ordered_end (void)
{
}
我推测,鉴于ordered
可能通常用于以下意义,因此从来就不是一个重要的用例:
#pragma omp parallel for ordered
for (...) {
result = expensive_computation()
#pragma omp ordered
{
append(results, result);
}
}
英特尔编译器的OpenMP运行时不会遇到这个缺陷。