Разница между #pragma omp parallel и #pragma omp parallel для

Dec 11 2020

Я новичок OpenMPи пытаюсь запустить программу, которая добавляет два массива с помощью OpenMP. В учебнике по OpenMP я узнал, что нам нужно использовать #pragma omp parallel for при использовании OpenMP в цикле for . Но я также пробовал то же самое с #pragma omp parallel, и он также дает мне правильный результат. Ниже приведены фрагменты кода того, что я пытаюсь передать.

#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];
       }
}

В чем разница между этими двумя?

Ответы

5 dreamcrash Dec 11 2020 at 15:14

В

#pragma omp parallel:

создаст parallel regionс командой threads, где каждый поток будет выполнять весь блок кода, который он parallel regionвключает.

Из OpenMP 5.1 можно прочитать более формальное описание:

Когда поток встречает параллельную конструкцию , создается группа потоков для выполнения параллельной области (..). Поток, который столкнулся с параллельной конструкцией, становится основным потоком новой группы с нулевым номером потока на время работы новой параллельной области. Все потоки в новой команде, включая основной поток, выполняют регион. После создания группы количество потоков в группе остается постоянным на протяжении всего этого параллельного региона.

В:

#pragma omp parallel for

создаст parallel region(как описано ранее), и для threadsэтой области будут назначены итерации цикла, который он включает, с использованием default chunk size, и, default scheduleчто обычно static . Однако имейте в виду, что они default scheduleмогут отличаться в зависимости от конкретной реализации OpenMPстандарта.

Из OpenMP 5.1 вы можете прочитать более формальное описание:

Конструкция workharing-loop указывает, что итерации одного или нескольких связанных циклов будут выполняться параллельно потоками в группе в контексте их неявных задач. Итерации распределяются по потокам, которые уже существуют в группе, выполняющей параллельную область, к которой привязана область цикла совместной работы .

Более того ,

Конструкция параллельного цикла - это ярлык для указания параллельной конструкции, содержащей конструкцию цикла с одним или несколькими связанными циклами и без других операторов.

Или, неофициально, #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 forс a chunk_size=1и static 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 < n; i += TOTAL_THREADS). В THREAD_IDдиапазоне от 0до TOTAL_THREADS - 1, и TOTAL_THREADSпредставляет общее количество потоков группы, созданной в параллельной области.

Я узнал, что нам нужно использовать #pragma omp parallel for при использовании OpenMP в цикле for. Но я также пробовал то же самое с #pragma omp parallel, и он также дает мне правильный результат.

Это дает вам тот же результат, потому что в вашем коде:

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

массив aи массив bтолько читаются, и только массив c[i]обновляется, и его значение не зависит от того, сколько раз iбудет выполняться итерация . Тем не менее, #pragma omp parallel forкаждый поток будет обновлять свои собственные i, тогда как #pragma omp parallelпотоки будут обновлять одни iи те же s, следовательно, переопределяя значения друг друга.

Теперь попробуйте сделать то же самое со следующим кодом:

#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 DanielLangr Dec 11 2020 at 15:16

Во втором случае цикл не распараллеливается. А именно, в каждом потоке выполняется весь цикл . Как правило, все, что находится внутри параллельной области, выполняется всеми потоками.

Вы можете дополнительно распараллелить цикл в уже существующей параллельной области следующим образом:

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