在 OpenMP 中并行化嵌套循环并使用更多线程执行内部循环

Posted

技术标签:

【中文标题】在 OpenMP 中并行化嵌套循环并使用更多线程执行内部循环【英文标题】:parallelize nested loop in OpenMP and do inner loop with more thread 【发布时间】:2013-07-22 23:07:46 【问题描述】:

我有这种嵌套循环:我想知道如何以最佳形式并行化它:

    第二个和第三个for 以及第五个和第六个for 运行相同 时间

    第一个和第四个for 串行

如果我有 24 个核心,并且想在 16 个线程之间划分外部并使用其余的与它们一起执行内部 for,例如使用 8 个线程执行第二个 for 而不仅仅是一个线程,我该怎么办?

void main()

//first_for
   for(int y=0; y< height; y++)

      //second_for 
      for(int x=0; x< width-1; x++)
   
     func1();
   
      //third_for
      for(int x=0; x< width-1; x++)
   
     func2();
   


//fourth_for
   for(int x=0; x<width; x++)

     //fifth_for
     for(int y=0; y< height-1; y++)
   
     func3();
   
     //sixth_for
     for(int y=0; y< height-1; y++)
   
     func4();
   


【问题讨论】:

但是第一个和第四个是否与其他 4 个同时运行? 第一个 first_for 和之后的第四个_for ? OpenMP 中嵌套循环的最佳处理是什么? 我认为您误解了 OpenMP 的嵌套并行性。如果您在 16 个线程上运行外部循环并在该范围内请求 8 个线程,您将获得(假设您的实现支持嵌套并行)16*8==128 线程总数;也就是说,外 16 根螺纹中的每根都有 8 根内螺纹。在 24 核机器上,这可能总是一个坏主意,因为线程争夺对处理器内核的访问权限,因为它们每个都会破坏其他缓存,等等。 是的@Mark你是对的Mark,以及在for中使用sections指令如何并行执行两个内部for,我注意到你的观点,但我想同时执行这两个for同一时间 【参考方案1】:

除了已经说过的内容之外,您可能还想显式启用嵌套并行性。可以通过运行时的库调用或环境变量(对于 OpenMP)来执行此操作。

欲了解更多信息,请查看此Oracle Docs。

【讨论】:

【参考方案2】:

关于并行性介绍,通常说越粗的级别越好,所以如果您可以在扩展良好的粗略级别添加并行指令,为什么还要添加嵌套并行?

所以基于可以同时运行的内容,我会这样编写主要内容:

int main()

     //first_for
     #pragma parallel for
     for(int y=0; y< height; y++)
     
          //second_for and third_for
      for(int x=0; x< width-1; x++)
     
          func1();
          func2();

      
  
 //fourth_for
 #pragma parallel for
 for(int x=0; x<width; x++)
 
      //fifth_for and  //sixth_for
     for(int y=0; y< height-1; y++)
    
          func3();
          func4();
     
  
 return 0;

    我们通过合并 2 个内部循环来增加每行和每列的工作量

    我们添加了 openMP 指令以根据您的核心数量将该计算循环拆分为更小的块。

    查看是否可以反转第一个循环,因为取决于您在内部执行的操作以及“图像”在内存中的映射方式,首先处理列可能会导致大量缓存错误....

编辑

您可以启用嵌套并行性,但它走错了路,过多的循环和线程访问不同的内存块只会降低性能,您还将拥有一个为 24 核设计的解决方案,可能无法与 32 扩展, 48 核等...但如果您坚持必须设置环境变量或调用 openMP 函数:

 call omp_set_nested()
 or
 set OMP_NESTED=TRUE|FALSE

在您的***循环上添加一个 openMP 子句以指定您想要的块大小以便只有 X 线程。

int  chunckSize = height / X;
#pragma parallel for schedule ( static , chunckSize)

openMP 线程团队应该由 24 个线程组成,但这样做只有 X 有工作要做。遵循嵌套循环的逻辑。

但这不是我推荐的解决方案!

【讨论】:

我想知道这是最好的形式吗?这个问题呢?如果我有 24 个内核并且想在 16 个线程之间划分外层并使用其余部分与它们一起执行内层,例如使用 8 个线程执行第二个而不是一个线程,我该怎么办? 我编辑了我的答案,但是你走的方式会导致奇怪的行为,更多的同步点(加入)等等......,

以上是关于在 OpenMP 中并行化嵌套循环并使用更多线程执行内部循环的主要内容,如果未能解决你的问题,请参考以下文章

OpenMP 如何处理嵌套循环?

OpenMP:嵌套并行化有啥好处?

如何优化并行嵌套循环?

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

OpenMP 矩阵乘法嵌套循环

OpenMP 循环运行代码比串行循环慢