#pragma omp parallel 和 #pragma omp parallel for 之间的区别

2 c c++ parallel-processing multithreading openmp

我是新手OpenMP,我一直在尝试运行一个使用 OpenMP 添加两个数组的程序。在 OpenMP 教程中,我了解到,在for循环上使用 OpenMP 时,我们需要使用#pragma omp parallel for但我也用#pragma omp parallel尝试过同样的事情,它也给了我正确的输出。下面是我想要传达的内容的代码片段。

#pragma omp parallel for
{
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}
Run Code Online (Sandbox Code Playgroud)

 #pragma omp parallel
{
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}
Run Code Online (Sandbox Code Playgroud)

这两者有什么区别?

dre*_*ash 6

#pragma omp parallel:

将创建一个parallel region由 组成的团队threads,其中每个线程将执行包含的整个代码块parallel region

OpenMP 5.1中可以读到更正式的描述:

当线程遇到并行构造时,会创建一组线程来执行并行区域 (..)。遇到并行构造的线程成为新团队的主线程,在新并行区域的持续时间内线程数为零。新团队中的所有线程(包括主线程)都会执行该区域。创建团队后,团队中的线程数在该并行区域的持续时间内保持不变。

这:

#pragma omp parallel for

将创建一个parallel region(如前所述),并且threads将使用 ,将其包含的循环的迭代分配给该区域的default chunk size,并且通常default schedule是。但请记住,标准的不同具体实施之间可能会有所不同。 staticdefault scheduleOpenMP

OpenMP 5.1中您可以阅读更正式的描述:

工作共享循环构造指定一个或多个关联循环的迭代将由团队中的线程在其隐式任务的上下文中并行执行。迭代分布在团队中已存在的线程中,该团队正在执行工作共享循环区域绑定到的并行区域

而且

并行循环构造是一种指定并行构造的快捷方式,该并行构造包含具有一个或多个关联循环且没有其他语句的循环构造。

或者非正式地,是构造函数与#pragma omp parallel for的组合。就您而言,这意味着:#pragma omp parallel#pragma omp for

#pragma omp parallel for
{
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}
Run Code Online (Sandbox Code Playgroud)

在语义和逻辑上都与:

#pragma omp parallel
{
      #pragma omp for
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}
Run Code Online (Sandbox Code Playgroud)

TL;DR:在您的示例中,with#pragma omp parallel for循环将在线程之间并行化(即,循环迭代将在线程之间划分),而 with #pragma omp parallel all线程将(并行)执行所有循环迭代。

为了使其更具说明性,使用4线程#pragma omp parallel, 将导致类似以下结果:

在此输入图像描述

#pragma omp parallel for使用 achunk_size=1和 a static schedule会导致类似的结果:

在此输入图像描述

从代码角度来看,循环将转换为逻辑上类似于以下内容的内容:

for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{  
    c[i]=a[i]+b[i];
}
Run Code Online (Sandbox Code Playgroud)

其中omp_get_thread_num()

omp_get_thread_num 例程返回当前组内调用线程的线程号。

omp_get_num_threads()

返回当前组中的线程数。在程序的连续部分中,omp_get_num_threads 返回 1。

或者换句话说,for(int i = THREAD_ID; i < n; i += TOTAL_THREADS). 范围THREAD_ID0TOTAL_THREADS - 1TOTAL_THREADS代表在并行区域上创建的团队线程总数。

我了解到,在 for 循环上使用 OpenMP 时,我们需要使用 #pragma omp parallel for。但我也用 #pragma omp parallel 尝试过同样的事情,它也给了我正确的输出。

它为您提供相同的输出,因为在您的代码中:

 c[i]=a[i]+b[i];
Run Code Online (Sandbox Code Playgroud)

arraya和 arrayb都是只读的,而 arrayc[i]是唯一被更新的,它的值不依赖于迭代i执行多少次。尽管如此,#pragma omp parallel for每个线程都会更新自己的值i,而#pragma omp parallel线程会更新相同的i值,因此会覆盖彼此的值。

现在尝试使用以下代码执行相同的操作:

#pragma omp parallel for
{
      for(int i=0;i<n;i++)
       {  
            c[i]= c[i] + a[i] + b[i];
       }
}
Run Code Online (Sandbox Code Playgroud)

#pragma omp for
{
      for(int i=0;i<n;i++)
       {  
            c[i] = c[i] + a[i] + b[i];
       }
}
Run Code Online (Sandbox Code Playgroud)

您会立即注意到差异。