Я новичок в 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 вы можете прочитать более формальное описание:
Конструкция worksharing-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];
}
}
Вкратце: в вашем примере с #pragma omp parallel for
цикл будет распараллелен между потоками (т. е. итерации цикла будут разделены между потоками), тогда как с #pragma omp parallel
все потоки будут выполнять (параллельно) все итерации цикла.
Чтобы сделать это более наглядным, с 4
потоками #pragma omp parallel
это приведет к чему-то вроде:
тогда как #pragma omp parallel for
с chunk_size=1
и статическим 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_num_threads возвращает 1.
или другими словами, for(int i = THREAD_ID; i < n; i += TOTAL_THREADS)
. Где THREAD_ID
варьируется от 0
до TOTAL_THREADS - 1
, а TOTAL_THREADS
представляет собой общее количество потоков команды, созданных в параллельном регионе.
Я узнал, что нам нужно использовать #pragma omp parallel в то время как используя 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];
}
Отвечает ли это на ваш вопрос? pragma omp parallel for vs. pragma omp parallel