OpenMP Nested Loop, что делает код?
У меня проблемы с пониманием того, как OpenMP работает с вложенными циклами. Пожалуйста помоги!
Я получил следующий код для параллельной работы:
#pragma omp parallel private(i)
{
for(i=0; i<n; i++)
{
#pragma omp for
for(j=0; j<n; j++)
{
if(asubsref(seed,j) > 0)
asubsref(bin,j) = asubsref(bin,j) + 1;
}
#pragma omp for
for(j=0; j<n; j++)
asubsref(seed,j) = asubsref(seed,j) - asubsref(w,i);
}
}
Однако я не совсем уверен, как работает этот код (я просто получил его по счастливой случайности). Вот что я думаю это делает...
Так for(i=0; i<n; i++)
разбивается на разные потоки и работает параллельно. Так как i
был объявлен private
каждый экземпляр цикла является "песочницей"; то есть любые изменения в j
оставаться в этой теме (по крайней мере, пока не завершатся все темы?). Я в замешательстве, потому что не декларирует #pragma omp for
приводит к сбою кода... Я не уверен, почему это так.
Если бы кто-нибудь мог рассказать мне, что делает этот код, я был бы очень признателен! Спасибо!
1 ответ
Это то, что обычно делают для того, чтобы уменьшить накладные расходы нескольких входов и существует в и из параллельной области. Сравните код из вашего вопроса со следующим эквивалентным кодом:
for (i=0; i<n; i++)
{
#pragma omp parallel for
for (j=0; j<n; j++)
{
if (asubsref(seed,j) > 0)
asubsref(bin,j) = asubsref(bin,j) + 1;
}
#pragma omp parallel for
for (j=0; j<n; j++)
asubsref(seed,j) = asubsref(seed,j) - asubsref(w,i);
}
Он запускает внешний цикл i
n
раз. В каждой итерации внешнего цикла он запускает два параллельных цикла j
разделив n
итерации среди потоков. Проблема здесь в том, что у вас есть две параллельные области внутри, каждая из которых активирована n
раз. Это может добавить значительные накладные расходы для определенного интервала значений n
(фактический интервал будет зависеть от многих факторов).
Чтобы уменьшить накладные расходы, нужно поместить весь код в параллельную область. Таким образом, каждый поток будет выполнять все итерации внешнего цикла, а внутренние итерации все равно будут разделены между потоками. Если вы удалите конструкции разделения, то внутренний цикл не будет распределен между потоками. Вместо этого каждый поток будет выполнять как полный диапазон внешних, так и внутренних итераций, например, asubsref(bin,j)
будет увеличен до num_threads
раз вместо одного (почему "до"? подсказка: незащищенный одновременный доступ к данным).
В большинстве случаев, когда запускается внешний цикл внутри параллельной конструкции, требуется, чтобы разные потоки продолжали помечать одни и те же итерации. Это может быть достигнуто с помощью барьера на конце тела петли:
#pragma omp parallel private(i)
{
for (i = 0; i < n; i++)
{
...
#pragma omp barrier
}
}
В вашем случае явный барьер не требуется, так как for
Конструкция совместного использования имеет неявный барьер в конце.