用一个线程做一个部分,用多个线程做一个 for 循环

Posted

技术标签:

【中文标题】用一个线程做一个部分,用多个线程做一个 for 循环【英文标题】:Doing a section with one thread and a for-loop with multiple threads 【发布时间】:2014-04-20 03:43:32 【问题描述】:

我正在使用 OpenMP,我想生成线程,以便一个线程执行一段代码并完成,与运行并行 for 循环迭代的 N 个线程并行。

执行应该是这样的:

Section A (one thread)       ||      Section B (parallel-for, multiple threads)
         |                   ||        | | | | | | | | | |
         |                   ||        | | | | | | | | | |
         |                   ||        | | | | | | | | | |
         |                   ||        | | | | | | | | | |
         |                   ||        | | | | | | | | | |
         V                   ||        V V V V V V V V V V

我不能只用#pragma omp once 编写并行for,因为我不希望执行A 部分的线程执行for 循环。

我试过这个:

#pragma omp parallel sections 
    #pragma omp section
    
         // Section A
    

    #pragma omp section
    
         // Section B;
         #pragma omp parallel for
         for (int i = 0; i < x; ++i)
             something();
    

但是,parallel-for 总是只用一个线程执行(我知道是因为我让循环体打印 omp_get_thread_num() 并且它们都是相同的数字,1 或 0 取决于执行的两个线程中的哪个线程第二个平行部分)。

我也试过

#pragma omp sections 
    #pragma omp section
    
         // Section A
    

    #pragma omp section
    
         // Section B;
         #pragma omp parallel for
         for (int i = 0; i < x; ++i)
             something();
    

这允许for循环与多个线程一起执行,但它使部分不并行,并且第一部分在第二部分之前顺序执行。

我需要的是这两种方法的组合,其中 for 循环的每次迭代和第一部分都是并行运行的。

【问题讨论】:

【参考方案1】:

嵌套并行度必须明确设置,因为它在大多数实现中默认禁用。按照 OpenMP 4.0 标准,您必须设置 OMP_NESTED 环境变量:

OMP_NESTED 环境变量通过以下方式控制嵌套并行性 设置nest-var ICV的初始值。这个的价值 环境变量必须为真或假。如果环境 变量设置为 true,启用嵌套并行;如果设置为 false,嵌套并行被禁用。程序的行为是 如果 OMP_NESTED 的值既不为真也不为 假的。

以下行应该适用于 bash:

 export OMP_NESTED=true

此外,正如@HristoIliev 在下面的评论中所指出的,您很可能想要设置OMP_NUM_THREADS 环境变量来调整性能。引用标准:

这个环境变量的值必须是正数的列表 整数值。列表的值将线程数设置为 用于相应嵌套级别的并行区域。

这意味着应该将OMP_NUM_THREADS 的值设置为类似于n,n-1,其中n 是CPU 内核的数量。例如:

export OMP_NUM_THREADS=8,7

对于 8 核系统(从下面的评论中复制的示例)。

【讨论】:

然而,应该注意的是,默认情况下,启用嵌套并行性时,嵌套团队将由 OMP_NUM_THREADS 线程组成​​,因此执行 for 工作共享构造的线程之一可能与线程执行部分 A。为了防止这种情况,应该将 OMP_NUM_THREADS 的值设置为类似于 n,n-1 其中n 是 CPU 内核的数量,例如export OMP_NUM_THREADS=8,7 用于 8 核系统。【参考方案2】:

也许下面的代码可以解决问题:

#pragma omp parallel for
for (int i = -1; i < x; ++i) 
    if (i==-1) 
        // Section A
    
    else 
        // Section B
        something();
    

但是,您需要确保 x >= 0。

【讨论】:

【参考方案3】:

您是否尝试过具有差异化活动的单个并行区域。例如 不需要嵌套并行。

#pragma omp_parallel 


#pragma omp task  
  once();

#pragma omp for 
  for(int i=0;i<N;i++)
    many(i);
  


您还可以并行使用基于 threadnum 的显式 if / else 区域并自己为第二个循环进行工作共享计算。

【讨论】:

以上是关于用一个线程做一个部分,用多个线程做一个 for 循环的主要内容,如果未能解决你的问题,请参考以下文章

如何使用线程去执行一个 有返回值的方法,并获取返回值?

python循环怎么用多线程去运行

C#多线程: 怎么知道 多个线程 执行完毕了?所有的线程执行完毕后 我要做处理

总结:任务线程和同步

python 线程理论部分

Java多线程与并发库7.多个线程之间共享数据的方式探讨