Разница между #pragma omp parallel и #pragma omp parallel для
Я новичок 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];
}
}
В чем разница между этими двумя?
Ответы
В
#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];
}
}
вы сразу заметите разницу.
Во втором случае цикл не распараллеливается. А именно, в каждом потоке выполняется весь цикл . Как правило, все, что находится внутри параллельной области, выполняется всеми потоками.
Вы можете дополнительно распараллелить цикл в уже существующей параллельной области следующим образом:
#pragma omp parallel
{
#pragma omp for
for (int i = 0; i < n; i++)
c[i] = a[i] + b[i];
}