D. Klauzule schedule
Paralelní oblast má na konci alespoň jednu bariéru a může mít v ní další bariéry. Na každé bariérě musí ostatní členové týmu čekat, až dorazí poslední vlákno. Aby se tato doba čekání minimalizovala, měla by se sdílená práce distribuovat tak, aby všechna vlákna dorazily do bariéry přibližně ve stejnou dobu. Pokud je některá z těchto sdílených prací obsažena v for
konstruktorech, schedule
lze pro tento účel použít klauzuli.
Pokud existují opakované odkazy na stejné objekty, volba plánu pro for
konstruktor může být určena především charakteristikami systému paměti, jako je přítomnost a velikost mezipaměti a zda jsou doby přístupu k paměti jednotné nebo neuniformní. Takové aspekty mohou znamenat, že každé vlákno konzistentně odkazuje na stejnou sadu prvků pole v řadě smyček, i když jsou některá vlákna přiřazena relativně méně práce v některých smyček. Toto nastavení lze provést pomocí static
plánu se stejnými hranicemi pro všechny smyčky. V následujícím příkladu se nula použije jako dolní mez ve druhé smyčce, i když k
by byla přirozenější, pokud plán nebyl důležitý.
#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);
}
Ve zbývajících příkladech se předpokládá, že přístup k paměti není dominantním aspektem. Pokud není uvedeno jinak, předpokládá se, že všechna vlákna přijímají srovnatelné výpočetní prostředky. V těchto případech volba plánu pro for
konstruktor závisí na všech sdílených pracích, které se mají provést mezi nejbližší předchozí bariérou a implicitní závěrečnou bariérou nebo nejbližší nadcházející bariérou nowait
, pokud existuje klauzule. Pro každý druh plánu ukazuje krátký příklad, jak tento druh plánu bude pravděpodobně nejlepší volbou. Stručná diskuze následuje po jednotlivých příkladech.
Plán static
je vhodný také pro nejjednodušší případ, paralelní oblast obsahující jednu for
konstruktoru, přičemž každá iterace vyžaduje stejné množství práce.
#pragma omp parallel for schedule(static)
for(i=0; i<n; i++) {
invariant_amount_of_work(i);
}
Plán static
je charakterizován vlastnostmi, které každé vlákno získá přibližně stejný počet iterací jako jakékoli jiné vlákno, a každé vlákno může nezávisle určit iterace přiřazené k němu. Proto není nutná žádná synchronizace k distribuci práce a za předpokladu, že každá iterace vyžaduje stejné množství práce, by se všechna vlákna měla dokončit přibližně ve stejnou dobu.
Pro tým p vláken, let ceiling(n/p) být celé číslo q, které splňuje n = p*q - r s 0 <= r p<. Jedna implementace static
plánu pro tento příklad by přiřadil iterace q prvním vláknům p-1 a iterace q-r poslednímu vláknu. Další přijatelná implementace by přiřadil iterace q prvním vlákenm p-r a iterace q-1 zbývajícím vláknům r . Tento příklad ukazuje, proč by program neměl spoléhat na podrobnosti konkrétní implementace.
Plán dynamic
je vhodný pro případ for
konstrukce s iteracemi vyžadujícími různé nebo dokonce nepředvídatelné množství práce.
#pragma omp parallel for schedule(dynamic)
for(i=0; i<n; i++) {
unpredictable_amount_of_work(i);
}
Plán dynamic
je charakterizován vlastností, že žádné vlákno čeká na bariéru déle, než trvá další vlákno ke spuštění konečné iterace. Tento požadavek znamená, že iterace musí být postupně přiřazeny podprocesům, jakmile budou k dispozici, se synchronizací pro každé přiřazení. Režijní náklady na synchronizaci je možné snížit zadáním minimální velikosti bloku k větší než 1, aby vlákna byla přiřazena k najednou, dokud nezůstane méně než k. To zaručuje, že vlákno nečeká na bariéru déle, než trvá další vlákno ke spuštění konečného bloku iterací (maximálně).
Plán dynamic
může být užitečný, pokud vlákna přijímají různé výpočetní prostředky, které mají mnohem stejný účinek jako různé množství práce pro každou iteraci. Podobně může být dynamický plán užitečný také v případě, že vlákna přicházejí do konstruktoru for
v různou dobu, i když v některých z těchto případů guided
může být plán vhodnější.
Plán guided
je vhodný pro případ, kdy vlákna mohou dorazit v různých časech v konstruktoru for
s každou iterací vyžadující přibližně stejné množství práce. K této situaci může dojít například v případě, že for
před konstruktorem předchází jeden nebo více oddílů nebo for
konstruktorů s klauzulemi nowait
.
#pragma omp parallel
{
#pragma omp sections nowait
{
// ...
}
#pragma omp for schedule(guided)
for(i=0; i<n; i++) {
invariant_amount_of_work(i);
}
}
Podobně jako dynamic
plán zaručuje, že vlákno nečeká na bariéru déle, než trvá jiné vlákno ke spuštění konečné iterace, nebo konečné k iterace, pokud je zadána velikost bloku k.guided
Mezi těmito plány je guided
plán charakterizován vlastností, že vyžaduje nejmenší synchronizace. U velikosti bloku k přiřadí typická implementace iterace q = ceiling(n/p) k prvnímu dostupnému vláknu, nastaví n na větší n-q a p*k a opakuje, dokud nebudou přiřazeny všechny iterace.
Pokud volba optimálního plánu není tak jasná, jak je tomu u těchto příkladů, plán je vhodný pro experimentování s různými plány a velikostmi bloků dat, runtime
aniž byste museli program upravovat a znovu kompilovat. Může být také užitečné, když optimální plán závisí (nějakým předvídatelným způsobem) na vstupních datech, na kterých je program použit.
Pokud chcete vidět příklad kompromisů mezi různými plány, zvažte sdílení 1000 iterací mezi osmi vlákny. Předpokládejme, že v každé iteraci existuje invariantní množství práce a použijte ji jako jednotku času.
Pokud se všechna vlákna spustí současně, static
plán způsobí spuštění konstruktoru v 125 jednotkách bez synchronizace. Předpokládejme ale, že jedno vlákno je 100 jednotek pozdě při příchodu. Zbývající sedm vláken pak čeká na bariéru na 100 jednotek a doba provádění celého konstruktoru se zvýší na 225.
Vzhledem k tomu, že jak plány dynamic
guided
, tak i plány zajišťují, že žádné vlákno nečeká na více než jednu jednotku na bariérě, zpožděné vlákno způsobí, že se časy provádění konstruktoru zvýší pouze na 138 jednotek, což se může zvýšit zpožděním ze synchronizace. Pokud taková zpoždění nejsou zanedbatelná, je důležité, aby počet synchronizací byl 1 000 pro dynamic
, ale pouze 41 pro guided
za předpokladu, že výchozí velikost bloku dat je jedna. S velikostí bloku 25 dynamic
a guided
oba končí ve 150 jednotkách a všechny zpoždění od požadovaných synchronizací, které nyní jsou číslo pouze 40 a 20, v uvedeném pořadí.