2012-11-04 11 views
11
vector<int> v; 

#pragma omp parallel for ordered schedule(dynamic, anyChunkSizeGreaterThan1) 
    for (int i = 0; i < n; ++i){ 
      ... 
      ... 
      ... 
#pragma omp ordered 
      v.push_back(i); 
    } 

Dies füllt v mit einer n sortierten sortierten Liste.Wie funktioniert die omp-Klausel?

Beim Erreichen des Blocks omp ordered müssen alle Threads warten, bis der Thread mit der geringsten Iteration abgeschlossen ist. Was aber, wenn keiner der Threads für diese spezifische Iteration ausgewählt wurde? Oder stellt die OpenMP-Laufzeitbibliothek immer sicher, dass die niedrigste Iteration von einem Thread behandelt wird?

Auch warum wird vorgeschlagen, dass ordered Klausel zusammen mit der dynamic schedule verwendet werden? Würde static schedule die Leistung beeinträchtigen?

Antwort

31

Die ordered-Klausel funktioniert folgendermaßen: Verschiedene Threads werden gleichzeitig ausgeführt, bis sie auf den Bereich ordered stoßen, der dann sequenziell in derselben Reihenfolge ausgeführt wird, in der er in einer seriellen Schleife ausgeführt wird. Dies ermöglicht immer noch einen gewissen Grad an Gleichzeitigkeit, insbesondere wenn der Codeabschnitt außerhalb der ordered Region eine beträchtliche Laufzeit aufweist.

Es gibt keinen besonderen Grund, dynamic Zeitplan statt static Zeitplan mit kleinen Chunk-Größe zu verwenden. Es hängt alles von der Struktur des Codes ab. Da ordered eine Abhängigkeit zwischen den Threads einführt, wenn sie mit mit Standard-Chunk-Größe verwendet wird, müsste der zweite Thread warten, bis der erste alle Iterationen beendet hat. Dann müsste der dritte Thread warten, bis der zweite seine Iterationen beendet hat (und daher auch für den ersten), und so weiter. Man könnte es leicht mit 3 Fäden visualisieren und 9 Iterationen (3 pro Thread):

tid List of  Timeline 
    iterations 
0 0,1,2  ==o==o==o 
1 3,4,5  ==.......o==o==o 
2 6,7,8  ==..............o==o==o 

= zeigt, dass der Thread Code parallel ausführt. o ist, wenn der Thread die ordered Region ausführt. . ist der Thread, der sich im Leerlauf befindet und darauf wartet, dass er wiederum die Region ordered ausführt. Mit schedule(static,1) würde folgendes passieren:

tid List of  Timeline 
    iterations 
0 0,3,6  ==o==o==o 
1 1,4,7  ==.o==o==o 
2 2,5,8  ==..o==o==o 

Ich glaube, der Unterschied in beiden Fällen ist mehr als offensichtlich. Mit schedule(dynamic) würden die obigen Bilder mehr oder weniger zufällig werden, da die Liste der jedem Thread zugewiesenen Iterationen nicht deterministisch ist. Es würde auch einen zusätzlichen Overhead hinzufügen. Es ist nur nützlich, wenn die Menge der Berechnung für jede Iteration unterschiedlich ist und es viel mehr Zeit für die Berechnung benötigt als der zusätzliche Aufwand für die Verwendung der dynamischen Planung.

Machen Sie sich keine Sorgen wegen der Iteration mit der niedrigsten Nummer. Es wird normalerweise mit dem ersten Thread im Team behandelt, um für die Ausführung von Code bereit zu sein.

+0

Ausgezeichnete Antwort Hristo! Alles klar jetzt, danke! –

+2

@ Cookie503, beachten Sie, dass, wenn die Chunk-Größe zu klein ist, Caching aufgrund verlorener Datenlokalität weniger nützlich wird. Dies könnte Ihre Leistung erheblich schlechter treffen als die implizierte Serialisierung. Experimentieren Sie mit verschiedenen Chunk-Größen, bis die beste Beschleunigung erreicht ist. Verwenden Sie "geordnete" Schleifen mit Bedacht und weichen Sie sie, falls möglich, selbst dann aus, wenn dies zu einem erhöhten Speicherbedarf führt - z. (Bei Ihrem bestimmten Beispiel) sollte anstelle eines Vektors ein einfaches vorher zugewiesenes Array (oder ein anderer Thread-sicherer Random-Access-Container) verwendet werden: 'arr [i] = i;' –