【问题标题】:Is it possible to do a reduction on an array with openmp?是否可以使用 openmp 对数组进行缩减?
【发布时间】:2011-04-16 01:34:18
【问题描述】:

OpenMP 本身是否支持减少表示数组的变量?

这将像下面这样工作......

float* a = (float*) calloc(4*sizeof(float));
omp_set_num_threads(13);
#pragma omp parallel reduction(+:a)
for(i=0;i<4;i++){
   a[i] += 1;  // Thread-local copy of a incremented by something interesting
}
// a now contains [13 13 13 13]

理想情况下,omp parallel for 会有类似的东西,如果你有足够多的线程让它有意义,那么累积将通过二叉树发生。

【问题讨论】:

  • 也许你可以解释一下你想要做什么。提供序列号可能会有所帮助。
  • 再挖掘一下,听起来“仅在 fortran 中”就是答案。我最终只是在循环之外分配了一个大型本地副本数组,让线程在 for 循环中累积到它们自己的副本,然后在 for 循环之后累积到一个全局数组中,仍然在并行区域内,在 a关键部分。
  • 更深入地挖掘,这里有一篇类似的研究论文,但它还没有在 openmp 中。 springerlink.com/content/tq76655852630525
  • 如果你想减少开销,你可以使用 atomic 而不是 critical 来保护单个添加(甚至是锁数组);您甚至可以使用共享数组而不是私有数组,并尝试使用自己的二进制归约。但这会很丑。
  • 我最终手动为数组的线程本地副本分配空间。每个线程将 1/8 的累加到其本地副本中,然后线程将其本地副本累加到 #pragma omp 关键块内的全局副本中。由于核心数 (8) 远小于 n,因此同步开销可以忽略不计。它不漂亮,但它有效。

标签: c++ arrays openmp reduction


【解决方案1】:

现在可以使用适用于 C 和 C++ 的 OpenMP 4.5 减少数组。这是一个例子:

#include <iostream>

int main()
{

  int myArray[6] = {};

  #pragma omp parallel for reduction(+:myArray[:6])
  for (int i=0; i<50; ++i)
  {
    double a = 2.0; // Or something non-trivial justifying the parallelism...
    for (int n = 0; n<6; ++n)
    {
      myArray[n] += a;
    }
  }
  // Print the array elements to see them summed   
  for (int n = 0; n<6; ++n)
  {
    std::cout << myArray[n] << " " << std::endl;
  } 
}

输出:

100
100
100
100
100
100

我用 GCC 6.2 编译了这个。您可以在此处查看哪些常用编译器版本支持 OpenMP 4.5 功能:https://www.openmp.org/resources/openmp-compilers-tools/

从上面的 cmets 中注意到,虽然这是一种方便的语法,但它可能会因为每个线程创建每个数组部分的副本而导致大量开销。

【讨论】:

  • 你的int main() 没有返回'int'让我有点恼火:D
【解决方案2】:

仅适用于 OpenMP 3.0 的 Fortran,并且可能仅适用于某些编译器。

请参阅最后一个示例(示例 3):

http://wikis.sun.com/display/openmp/Fortran+Allocatable+Arrays

【讨论】:

  • 现在可以从 OpenMP 4.5 开始;下面看陈江的回答。基本上,您必须指定 数组部分(请参阅 OpenMP 4.5 规范的第 2.4 节,第 44 页)。你的#pragma 规范看起来像这样:#pragma omp parallel reduction(+:a[:4]) 但是要小心,你必须意识到每个线程都会分配它自己版本的数组部分;如果您在具有许多线程的大型数组上执行此操作,则可能会使您的内存需求爆炸。
【解决方案3】:

现在最新的 openMP 4.5 规范支持减少 C/C++ 数组。 http://openmp.org/wp/2015/11/openmp-45-specs-released/

而且最新的 GCC 6.1 也支持了这个特性。 http://openmp.org/wp/2016/05/gcc-61-released-supports-openmp-45/

但我还没有尝试过。希望其他人可以测试此功能。

【讨论】:

    【解决方案4】:

    OpenMP 无法对数组或结构类型变量执行归约(请参阅restrictions)。

    您可能还想阅读privateshared 子句。 private 声明一个变量为每个线程私有,而shared 声明一个变量在所有线程之间共享。我还发现这个question 的答案对于 OpenMP 和数组非常有用。

    【讨论】:

      【解决方案5】:

      OpenMP 可以从 OpenMP 4.5 开始执行此操作,并且 GCC 6.3(可能更低)支持它。示例程序如下所示:

      #include <vector>
      #include <iostream>
      
      int main(){
        std::vector<int> vec;
      
        #pragma omp declare reduction (merge : std::vector<int> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end()))
      
        #pragma omp parallel for default(none) schedule(static) reduction(merge: vec)
        for(int i=0;i<100;i++)
          vec.push_back(i);
      
        for(const auto x: vec)
          std::cout<<x<<"\n";
      
        return 0;
      }
      

      请注意,omp_outomp_in 是特殊变量,declare reduction 的类型必须与您计划减少的向量相匹配。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-09
        • 1970-01-01
        • 1970-01-01
        • 2021-06-17
        • 2021-04-28
        • 1970-01-01
        • 1970-01-01
        • 2019-02-09
        相关资源
        最近更新 更多