OpenMP 并行用于 - 多个并行用于的 Vs。一个并行,其中包含多个 for
Posted
技术标签:
【中文标题】OpenMP 并行用于 - 多个并行用于的 Vs。一个并行,其中包含多个 for【英文标题】:OpenMP parallel for -- Multiple parallel for's Vs. one parallel that includes within it multiple for's 【发布时间】:2021-08-11 06:12:18 【问题描述】:我正在通过Using OpenMP。作者比较和对比了以下两种结构:
//Construct 1
#pragma omp parallel for
for( ... )
/* Work sharing loop 1 */
...
#pragma omp parallel for
for( ... )
/* Work sharing loop N */
反对
//Construct 2
#pragma omp parallel
#pragma omp for
for( ... )
/* Work sharing loop 1 */
...
#pragma omp for
for( ... )
/* Work sharing loop N */
他们说构造 2
隐含的障碍较少,并且可能存在缓存 循环之间的数据重用。这种方法的缺点是一个 不能再在每个循环的基础上调整线程数,但是 这通常不是真正的限制。
我很难理解 Construct 2 如何具有更少的隐含障碍。由于#pragma omp for
,在每个 for 循环之后,构造 2 中是否没有隐含的障碍?那么,在每种情况下,隐含障碍的数量是否都相同,N
?也就是Construct 2中不是先出现第一个循环,以此类推,然后最后执行N
th for循环吗?
另外,Construct 2 如何更利于循环之间的缓存重用?
【问题讨论】:
【参考方案1】:我很难理解 Construct 2 如何减少 隐含的障碍。在 Construct 2 之后是否没有隐含的障碍? 每个 for 循环由于#pragma omp for?所以,在每种情况下,不是 隐含障碍的数量相同,N?也就是说,在 构造 2,第一个循环首先发生,依此类推,然后 最后执行第 N 个 for 循环?
我没有读过这本书,但根据您所展示的内容,实际上是相反的,即:
//Construct 1
#pragma omp parallel for
for( ... )
/* Work sharing loop 1 */
// <-- implicit barrier
...
#pragma omp parallel for
for( ... )
/* Work sharing loop N */
// <-- implicit barrier.
有N个隐含障碍(在每个平行区域的末尾),而第二个代码:
//Construct 2
#pragma omp parallel
#pragma omp for
for( ... )
/* Work sharing loop 1 */
<-- implicit barrier
...
#pragma omp for
for( ... )
/* Work sharing loop N */
<-- implicit barrier
<-- implicit barrier
有 N+1 个障碍(在每个 for + 平行区域的末尾。
实际上,在这种情况下,由于最后两个隐式障碍之间没有计算,因此可以将nowait
添加到最后一个#pragma omp for
以消除其中一个冗余障碍。
第二个代码比第二个代码具有更少隐式障碍的一种方法是在#pragma omp for
子句中添加一个nowait
子句。
从您所展示的书的链接中:
最后,使用 OpenMP 考虑了可能影响 OpenMP 的趋势 发展,提供对未来可能性的一瞥 OpenMP 3.0 从当前 OpenMP 2.5 的优势来看。 多核电脑的使用越来越多,需要一个全面的 标准接口的介绍和概述清晰。
所以这本书使用的是old OpenMP 2.5 标准,从standard 关于loop 构造函数的内容我们可以读到:
在循环构造函数的末尾有一个隐式屏障 除非指定了 nowait 子句。
nowait
不能添加到 parallel
构造函数,但可以添加到 for
构造函数。因此,如果可以将nowait
子句添加到#pragma omp for
子句,则第二个代码可能 具有更少的隐式障碍。然而,事实上,第二个代码实际上比第一个代码具有更多隐含的障碍。
另外,Construct 2 如何更利于循环之间的缓存重用?
如果您在线程之间使用循环迭代的static
分布(例如, 第二个代码中的#pragma omp for scheduler(static, ...)
,相同的线程将使用相同的循环迭代。例如, 有两个线程,让我们称它们为 Thread A
和 Thread B
。如果我们假设具有 chunk=1
、Thread A
和 B
的 静态 分布将适用于奇数和偶数迭代每个循环,分别。因此,根据实际的应用程序代码,这可能意味着这些线程将使用给定数据结构的相同内存位置(例如,相同的数组位置)。 p>
在第一个代码中,理论上(但这将取决于具体的 OpenMP 实现),因为有两个不同的并行区域,不同的线程可以在两个循环之间选择相同的循环迭代.换句话说,在我们使用两个线程的示例中,不能保证在一个循环中计算偶数(或奇数)的同一线程会在其他循环中计算相同的数字。
【讨论】:
以上是关于OpenMP 并行用于 - 多个并行用于的 Vs。一个并行,其中包含多个 for的主要内容,如果未能解决你的问题,请参考以下文章
哪个库用于迭代 1M*1k 次的并行 for 循环,OpenMP 或 boost::thread?