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);
}

Он запускает внешний цикл in раз. В каждой итерации внешнего цикла он запускает два параллельных цикла jразделив n итерации среди потоков. Проблема здесь в том, что у вас есть две параллельные области внутри, каждая из которых активирована n раз. Это может добавить значительные накладные расходы для определенного интервала значений n (фактический интервал будет зависеть от многих факторов).

Чтобы уменьшить накладные расходы, нужно поместить весь код в параллельную область. Таким образом, каждый поток будет выполнять все итерации внешнего цикла, а внутренние итерации все равно будут разделены между потоками. Если вы удалите конструкции разделения, то внутренний цикл не будет распределен между потоками. Вместо этого каждый поток будет выполнять как полный диапазон внешних, так и внутренних итераций, например, asubsref(bin,j) будет увеличен до num_threads раз вместо одного (почему "до"? подсказка: незащищенный одновременный доступ к данным).

В большинстве случаев, когда запускается внешний цикл внутри параллельной конструкции, требуется, чтобы разные потоки продолжали помечать одни и те же итерации. Это может быть достигнуто с помощью барьера на конце тела петли:

#pragma omp parallel private(i)
{
    for (i = 0; i < n; i++)
    {
        ...
        #pragma omp barrier
    }
}

В вашем случае явный барьер не требуется, так как for Конструкция совместного использования имеет неявный барьер в конце.

Другие вопросы по тегам