Поделиться через


D. Предложение schedule

Параллельный регион имеет по крайней мере один барьер, в конце и может иметь дополнительные барьеры внутри него. На каждом барьере остальные члены команды должны ждать последнего потока. Чтобы свести к минимуму это время ожидания, необходимо распределить общую работу таким образом, чтобы все потоки прибыли на барьер примерно в то же время. Если некоторые из этих общих работ содержатся в for конструкциях, schedule предложение можно использовать для этой цели.

При наличии повторяющихся ссылок на одни и те же объекты выбор расписания для for конструкции может определяться главным образом характеристиками системы памяти, например наличием и размером кэшей, а также временем доступа к памяти или несоединенной. Такие рекомендации могут привести к тому, что каждый поток последовательно ссылается на один набор элементов массива в ряде циклов, даже если некоторые потоки назначаются относительно меньше работы в некоторых циклах. Эту настройку static можно выполнить с помощью расписания с одинаковыми границами для всех циклов. В следующем примере нулевое значение используется в качестве нижней границы во втором цикле, хотя k было бы более естественным, если расписание не было бы важным.

#pragma omp parallel
{
#pragma omp for schedule(static)
  for(i=0; i<n; i++)
    a[i] = work1(i);
#pragma omp for schedule(static)
  for(i=0; i<n; i++)
    if(i>=k) a[i] += work2(i);
}

В остальных примерах предполагается, что доступ к памяти не является доминирующим фактором. Если не указано иное, предполагается, что все потоки получают сопоставимые вычислительные ресурсы. В этих случаях выбор расписания для for конструкции зависит от всех общих работ, которые должны выполняться между ближайшим предыдущим барьером и подразумеваемым закрывающим барьером или ближайшим барьером, если есть nowait предложение. Для каждого типа расписания короткий пример показывает, как этот тип расписания, скорее всего, будет лучшим выбором. Краткое обсуждение следует каждому примеру.

Расписание static также подходит для простейшей ситуации, параллельной области, содержащей одну for конструкцию, с каждой итерацией, требующей одинакового объема работы.

#pragma omp parallel for schedule(static)
for(i=0; i<n; i++) {
  invariant_amount_of_work(i);
}

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

Для команды потоков p пусть потолок (n/p) будет целым числом q, которое удовлетворяет n = p*q - r с 0 <= r .< Одна реализация static расписания для этого примера будет назначать итерации q первым потокам p-1 и итерации q-r последнему потоку. Другая допустимая реализация присваивает итерации q первым потокам p-r и итерации q-1 остальным потокам r . В этом примере показано, почему программа не должна полагаться на детали конкретной реализации.

Расписание dynamic подходит для случая for конструкции с итерациями, требующими различных или даже непредсказуемых объемов работы.

#pragma omp parallel for schedule(dynamic)
  for(i=0; i<n; i++) {
    unpredictable_amount_of_work(i);
}

Расписание dynamic характеризуется свойством, которое поток не ожидает в барьере дольше, чем требуется другому потоку для выполнения окончательной итерации. Это требование означает, что при каждом назначении необходимо назначать итерации по одному потоку по мере их доступности с синхронизацией для каждого назначения. Затраты на синхронизацию можно уменьшить путем указания минимального размера блока, превышающего 1, чтобы потоки были назначены k за раз до тех пор, пока не останется меньше k. Это гарантирует, что поток не ожидает на барьере дольше, чем требуется другой поток для выполнения окончательного фрагмента (в большинстве) итерации k .

Расписание dynamic может быть полезно, если потоки получают различные вычислительные ресурсы, что имеет тот же эффект, что и различные объемы работы для каждой итерации. Аналогичным образом динамический график также может быть полезным, если потоки приходят в for конструкцию в разное время, хотя в некоторых из этих случаев guided расписание может быть предпочтительнее.

Расписание guided подходит для случая, когда потоки могут поступать в различные периоды в for конструкции с каждой итерацией, требующей примерно одного объема работы. Эта ситуация может произойти, если, например, конструкция for предшествует одному или нескольким разделам или for конструкциям с nowait предложениями.

#pragma omp parallel
{
  #pragma omp sections nowait
  {
    // ...
  }
  #pragma omp for schedule(guided)
  for(i=0; i<n; i++) {
    invariant_amount_of_work(i);
  }
}

Например dynamic, расписание гарантирует, guided что поток не ожидает на барьере дольше, чем требуется другому потоку для выполнения окончательной итерации или окончательных итераций k , если указан размер блока k . Среди таких расписаний расписание характеризуется свойством, guided которое требует наименьших синхронизаций. Для размера блока k типичная реализация будет назначать итерации q = ceiling(n/p) первому доступному потоку, задать n больше n-q и p*k, а затем повторять до тех пор, пока не будут назначены все итерации.

Если выбор оптимального расписания не так четко, как и в этих примерах, runtime расписание удобно для экспериментирования с различными расписаниями и размерами блоков, не изменяя и перекомпилируя программу. Это также может быть полезно, если оптимальное расписание зависит (в некотором прогнозируемом способе) от входных данных, к которым применяется программа.

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

Если все потоки начинаются одновременно, static расписание приведет к выполнению конструкции в 125 единиц без синхронизации. Но предположим, что один поток составляет 100 единиц в конце прибытия. Затем оставшиеся семь потоков ожидают 100 единиц в барьере, а время выполнения для всей конструкции увеличивается до 225.

dynamic Так как оба плана guided и расписания не должны ожидать более одной единицы на барьере, задержка потока приводит к увеличению времени выполнения конструкции только до 138 единиц, возможно, увеличением задержки синхронизации. Если такие задержки не являются незначительными, важно, что число синхронизаций равно 1000, dynamic но только 41 для guided, если размер блока по умолчанию равен одному. С размером блока 25, dynamic и guided оба заканчиваются в 150 единицах, а также любые задержки от необходимых синхронизаций, которые теперь число только 40 и 20 соответственно.