Уменьшите накладные расходы вилки/соединения OpenMP путем отделять # omp параллельное и #omp для

Я читаю книгу введение в параллельное программирование Питер С. Пачеко. В разделе 5.6.2 он дал интересное обсуждение о сокращении накладных расходов на вилку/соединение. Рассмотрим алгоритм сортировки нечетно-четной транспозиции:

for(phase=0; phase < n; phase++){
    if(phase is even){
#       pragma omp parallel for default(none) shared(n) private(i)
        for(i=1; i<n; i+=2){//meat}
    }
    else{
#       pragma omp parallel for default(none) shared(n) private(i)
        for(i=1; i<n-1; i+=2){//meat}
    }
}

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

# pragma omp parallel default(none) shared(n) private(i, phase)
for(phase=0; phase < n; phase++){
    if(phase is even){
#       pragma omp for
        for(i=1; i<n; i+=2){//meat}
    }
    else{
#       pragma omp for
        for(i=1; i<n-1; i+=2){//meat}
    }
}

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

однако я с подозрением отношусь к правильности второй версии. В моем понимании,#pragma omp parallel директива инициирует группу потоков и позволяет потокам параллельно выполнять следующий структурированный блок. В этом случае структурированным блоком должен быть весь внешний for-loop for(phase=0 ...). Тогда не должно ли быть так, что весь внешний цикл выполняется четыре раза, когда используются 4 потока? То есть, если n=10, затем 40 итераций будут выполняться на 4 потоках. Что не так с моим пониманием? А как же omp parallel (без for) играть со следующим for-loop, как указано выше?

1 ответов


вторая версия верна.

согласно спецификации OpenMP, a