【问题标题】:Difference between #pragma omp parallel and #pragma omp parallel for#pragma omp parallel 和 #pragma omp parallel for 之间的区别
【发布时间】:2021-03-22 15:49:53
【问题描述】:

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

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

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

这两者有什么区别?

【问题讨论】:

标签: c++ c multithreading parallel-processing openmp


【解决方案1】:

#pragma omp parallel:

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

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

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

#pragma omp parallel for

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

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

worksharing-loop 结构指定一个或一个的迭代 更多相关的循环将由线程中的线程并行执行 团队在他们的隐含任务的背景下。 迭代是 分布在团队中已经存在的线程中 执行工作共享循环区域所在的并行区域 绑定

Moreover,

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

或者非正式地,#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];
       }
}

在语义上和逻辑上与:

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

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

为了更便于说明,使用4 线程和#pragma omp parallel,会产生如下结果:

#pragma omp parallel forchunk_size=1static schedule 会导致类似:

在代码方面,循环将被转换为逻辑上类似于:

for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{  
    c[i]=a[i]+b[i];
}

在哪里omp_get_thread_num()

omp_get_thread_num 例程返回线程号,在 调用线程的当前团队。

omp_get_num_threads()

返回当前团队中的线程数。在一个顺序 程序 omp_get_num_threads 的部分返回 1。

或者换句话说,for(int i = THREAD_ID; i &lt; n; i += TOTAL_THREADS)。其中THREAD_ID 范围从0TOTAL_THREADS - 1TOTAL_THREADS 表示在并行区域上创建的团队的线程总数。

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

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

 c[i]=a[i]+b[i];

数组a和数组b是只读的,数组c[i]是唯一被更新的,它的值不取决于迭代i会执行多少次。尽管如此,使用#pragma omp parallel for,每个线程都会更新自己的i,而使用#pragma omp parallel,线程将更新相同的is,因此会覆盖彼此的值。

现在尝试用下面的代码做同样的事情:

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

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

您会立即注意到不同之处。

【讨论】:

    【解决方案2】:

    在第二种情况下,循环没有并行化。即整个循环在每个线程中执行。通常,并行区域内的任何内容都由所有线程执行。

    您可以在已经存在的并行区域中额外并行化循环,如下所示:

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

    【讨论】:

      猜你喜欢
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-07
      • 2021-11-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多