Можно ли сделать сокращение на массиве с помощью openmp?

Поддерживает ли 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, и если у вас достаточно большое количество потоков, чтобы это имело смысл, накопление происходило бы через двоичное дерево.

5 ответов

Решение

Только в Фортране в OpenMP 3.0 и, вероятно, только с определенными компиляторами.

Смотрите последний пример (Пример 3) на:

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

Сокращение массива теперь возможно с OpenMP 4.5 для C и C++. Вот пример:

#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, здесь: http://www.openmp.org/resources/openmp-compilers/

Обратите внимание на комментарии выше, что, хотя это удобный синтаксис, он может вызвать много накладных расходов при создании копий каждого раздела массива для каждого потока.

Теперь последняя спецификация 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/

Но я еще не попробовал. Жаль, что другие могут проверить эту функцию.

OpenMP не может выполнять сокращения переменных массива или типа структуры (см. Ограничения).

Вы также можете прочитать о private а также shared статьи. private объявляет переменную частной для каждого потока, где как shared объявляет переменную, которая будет совместно использоваться всеми потоками. Я также нашел ответ на этот вопрос очень полезным в отношении OpenMP и массивов.

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_out а также omp_in специальные переменные и что тип declare reduction должен соответствовать вектору, который вы планируете уменьшить.

Другие вопросы по тегам