Эффективное распараллеливание внутреннего цикла - PullRequest
0 голосов
/ 27 октября 2018

У меня есть этот последовательный код:

for (unsigned item = 0; item < totalItems; ++item) { // Outer loop
// Outer body
  for (unsigned j = 0; j < maxSize; ++j) { // Inner loop
  // Inner body
  }
}

Моя цель - просто распараллелить внутренний цикл. Это можно сделать так:

for (unsigned item = 0; item < totalItems; ++item) { // Outer loop
// Outer body
  #pragma omp parallel for
  for (unsigned j = 0; j < maxSize; ++j) { // Inner loop
  // Inner body
  }
}

Проблема этого кода в том, что при каждом запуске внешнего цикла создаются новые потоки. Чтобы ускорить этот код, я хочу заранее создать команду потоков и использовать их несколько раз. Я обнаружил, что для этой цели существует директива #pragma omp for.

#pragma omp parallel
for (unsigned item = 0; item < totalItems; ++item) { // Outer loop
// Outer body
  #pragma omp for
  for (unsigned j = 0; j < maxSize; ++j) { // Inner loop
  // Inner body
  }
}

Однако, если я правильно понимаю, использование директивы #pragma omp parallel приводит к тому, что внешний цикл запускается несколько раз. Это правильно?

Редактировать : Вот более подробный пример:

// Let say that the image is represented as an array of pixels
// where pixels is just one integer.
std::vector<Image> images = getImages();

for (auto & image : images) { // Loop over all images
  #pragma omp parallel for
  for (unsigned j = 0; j < image.size(); ++j) { // Loop over each pixel
    image.at(j) += addMagicConstant(j);      
  }
}

Цель : я хочу порождать команду потоков, а затем использовать их многократно для распараллеливания только внутреннего цикла (= цикл по пикселям изображения).

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Ваш код совершенно действителен и действительно будет работать:

#pragma omp parallel
for (unsigned item = 0; item < totalItems; ++item) { // Outer loop
// Outer body
  #pragma omp for
  for (unsigned j = 0; j < maxSize; ++j) { // Inner loop
  // Inner body
  }
}

#pragma omp parallel будет порождать потоки.Каждый поток будет затем проходить через внешний цикл.На каждой итерации цикла потоки будут нажимать #pragma omp for, и внутренний цикл будет распределен между потоками.Существует неявный барьер в конце каждого omp for блока, поэтому потоки будут ожидать завершения внутреннего цикла, прежде чем перейти к следующей итерации внешнего цикла.

Наличие распределенного цикла omp for внутри другогоЦикл for или while, или в условном разделе возможен, если гарантируется, что все потоки попадут в цикл.

Однако запрещено использовать такие конструкции, как:

#pragma omp parallel
for (unsigned ii= 0; ii< omp_thread_num(); ++ii) { // Number of iteration of outer loop depends on the thread
// Outer body
  #pragma omp for
  for (unsigned j = 0; j < maxSize; ++j) { // Inner loop
  // Inner body
  }
}

или

#pragma omp parallel
if(condition_depending_on_thread_num) { 
  #pragma omp for
  for (unsigned j = 0; j < maxSize; ++j) { // Loop
  // Inner body
  }
}
0 голосов
/ 27 октября 2018

Вы пробовали:

#pragma omp parallel for
for (unsigned item = 0; item < totalItems; ++item) { // Outer loop
  for (unsigned j = 0; j < maxSize; ++j) { // Inner loop
  }
}
...