openMP 嵌套并行 for 循环与内部并行 for

Posted

技术标签:

【中文标题】openMP 嵌套并行 for 循环与内部并行 for【英文标题】:openMP nested parallel for loops vs inner parallel for 【发布时间】:2012-05-19 10:11:24 【问题描述】:

如果我像这样使用嵌套的并行循环:

#pragma omp parallel for schedule(dynamic,1)
for (int x = 0; x < x_max; ++x) 
    #pragma omp parallel for schedule(dynamic,1)
    for (int y = 0; y < y_max; ++y)  
    //parallelize this code here
   
//IMPORTANT: no code in here

这是否等同于:

for (int x = 0; x < x_max; ++x) 
    #pragma omp parallel for schedule(dynamic,1)
    for (int y = 0; y < y_max; ++y)  
    //parallelize this code here
   
//IMPORTANT: no code in here

除了创建新任务之外,外部并行是否可以做任何事情?

【问题讨论】:

【参考方案1】:

如果您的编译器支持 OpenMP 3.0,您可以使用 collapse 子句:

#pragma omp parallel for schedule(dynamic,1) collapse(2)
for (int x = 0; x < x_max; ++x) 
    for (int y = 0; y < y_max; ++y)  
    //parallelize this code here
    
//IMPORTANT: no code in here

如果不支持(例如仅支持 OpenMP 2.5),有一个简单的解决方法:

#pragma omp parallel for schedule(dynamic,1)
for (int xy = 0; xy < x_max*y_max; ++xy) 
    int x = xy / y_max;
    int y = xy % y_max;
    //parallelize this code here

您可以使用omp_set_nested(1); 启用嵌套并行性,并且您的嵌套omp parallel for 代码将起作用,但这可能不是最好的主意。

顺便问一下,为什么是动态调度?是否每次循环迭代都在非常量时间内进行评估?

【讨论】:

我使用的是VS2008,所以我认为我不能使用崩溃,我考虑过你提到的第二种方式,但希望不必大幅更改代码。它用于光线追踪器,因此一些主光线可能需要比其他光线长 10 倍的时间 显然即使是 VS2010 也只支持 OpenMP 2.0。 请注意,整数除法和取模是相对昂贵的操作。如果循环体做的工作很少,开销可能很大。 在最后一个例子中xy不应该被标记为private吗? @ars,这两个变量都在并行区域内声明,因此预定为private。另外,由于外部作用域中不存在变量,添加private(x,y)会报错。【参考方案2】:

没有。

第一个#pragma omp parallel 将创建一组并行线程,然后第二个将尝试为每个原始线程创建另一个团队,即一组团队。然而,在几乎所有现有的实现中,第二个团队只有一个线程:第二个并行区域基本上没有被使用。因此,您的代码更像是

#pragma omp parallel for schedule(dynamic,1)
for (int x = 0; x < x_max; ++x) 
    // only one x per thread
    for (int y = 0; y < y_max; ++y)  
        // code here: each thread loops all y
    

如果您不希望这样做,而只是并行化内部循环,您可以这样做:

#pragma omp parallel
for (int x = 0; x < x_max; ++x) 
    // each thread loops over all x
#pragma omp for schedule(dynamic,1)
    for (int y = 0; y < y_max; ++y)  
        // code here, only one y per thread
    

【讨论】:

我明白了,我考虑过这一点,但它似乎很反直觉。因此,如果我想要在所有迭代中“并行”,我应该将“并行”放在内部循环中? @Bunnit 我不知道你想要什么,但我添加了我的答案。 @Bunnit 我认为我的第二个解决方案至少应该达到与 Hrito Iliev 的第二个相同的速度,但在概念上更加清晰。如果内部循环中的工作负载在 y 的不同值之间没有太大差异,则第一个解决方案甚至更可取。在所有情况下,您都可以并行化双循环,因为每一对 (x,y) 仅由整个线程团队调用一次。

以上是关于openMP 嵌套并行 for 循环与内部并行 for的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenMP 在 C、C++ 中并行化嵌套 for 循环的几种方法之间的区别

OpenMP 如何处理嵌套循环?

使用 SSE 矢量化在 OpenMP 中将内部循环与残差计算并行化

OpenMP 嵌套循环任务并行性,计数器未给出正确结果

如何优化并行嵌套循环?

OPENMP F90/95 嵌套 DO 循环 - 与串行实现相比得到改进的问题