баллы sehe - особенно «это зависит» и «профиль» - чрезвычайно важны.
Обычно, однако, вы не захотите иметь вложенные параллельные циклы, если внешний цикл достаточно велик, чтобы все ядра были заняты. Дополнительные издержки другого параллельного участка внутри цикла, вероятно, дороже, чем выгода от дополнительных небольших кусочков работы.
Обычный способ решения этой проблемы - динамическое планирование внешнего цикла, чтобы тот факт, что каждая итерация цикла имеет различную длину типа, не вызывает проблем с балансировкой нагрузки (поскольку итерация i==N-1
завершается практически сразу в то время как итерация i==0
занимает вечность)
#pragma omp parallel for default(none) shared(N) schedule(dynamic)
for(int i = 0; i < N; i++) {
for(int k = i; k < N; k++) {
// k starts from i, not from 0...
}
}
Прагма свертывания очень полезна для существенного избавления от вложенности и особенно полезна, если внешний цикл мал (например, N < num_threads
):
#pragma omp parallel for default(none) shared(N) collapse(2)
for(int i = 0; i < N; i++) {
for(int k = 0 ; k < N; k++) {
}
}
Таким образом, две петли складываются в одну, и уменьшается количество порций, что означает меньшие накладные расходы. Но это не сработает в этом случае, потому что диапазоны цикла не фиксированы; Вы не можете collapse
цикл, границы цикла которого изменяются (например, с i
).