Unterschied zwischen #pragma omp parallel und #pragma omp parallel für
Ich bin neu in OpenMP
und habe versucht, ein Programm auszuführen, das mit OpenMP zwei Arrays hinzufügt. Im OpenMP-Tutorial habe ich gelernt, dass wir #pragma omp parallel verwenden müssen, während wir OpenMP in der for- Schleife verwenden. Aber ich habe das gleiche auch mit #pragma omp parallel versucht und es gibt mir auch die richtige Ausgabe. Unten sind die Code-Schnipsel von dem, was ich zu vermitteln versuche.
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
und
#pragma omp parallel
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
Was ist der Unterschied zwischen diesen beiden?
Antworten
Das
#pragma omp parallel
::
erstellt ein parallel region
mit einem Team von threads
, wobei jeder Thread den gesamten Codeblock ausführt, den das eingeschlossene enthält parallel region
.
Aus OpenMP 5.1 kann man eine formellere Beschreibung lesen:
Wenn ein Thread auf ein paralleles Konstrukt trifft , wird ein Team von Threads erstellt , um den parallelen Bereich (..) auszuführen. Der Thread, der auf das parallele Konstrukt gestoßen ist, wird zum primären Thread des neuen Teams mit einer Thread-Nummer von Null für die Dauer des neuen parallelen Bereichs. Alle Threads im neuen Team, einschließlich des primären Threads, führen die Region aus. Sobald das Team erstellt wurde, bleibt die Anzahl der Threads im Team für die Dauer dieser parallelen Region konstant.
Das:
#pragma omp parallel for
wird ein parallel region
(wie zuvor beschrieben) erstellen , und dem threads
von diesem Bereich werden die Iterationen der Schleife, die es einschließt, unter Verwendung des default chunk size
und des, default schedule
das typischerweise ist , zugewiesen static
. Beachten Sie jedoch, dass sich die default schedule
Unterschiede zwischen den verschiedenen konkreten Implementierungen des OpenMP
Standards unterscheiden können.
In OpenMP 5.1 können Sie eine formellere Beschreibung lesen:
Das Worksharing-Loop-Konstrukt gibt an, dass die Iterationen einer oder mehrerer zugeordneter Schleifen von Threads im Team im Kontext ihrer impliziten Aufgaben parallel ausgeführt werden. Die Iterationen werden auf Threads verteilt, die bereits in dem Team vorhanden sind, das den parallelen Bereich ausführt, an den der Worksharing-Loop-Bereich gebunden ist .
Darüber hinaus ,
Das Parallelschleifenkonstrukt ist eine Verknüpfung zum Angeben eines Parallelkonstrukts, das ein Schleifenkonstrukt mit einer oder mehreren zugeordneten Schleifen und keinen anderen Anweisungen enthält.
Oder informell #pragma omp parallel for
ist eine Kombination des Konstruktors #pragma omp parallel
mit #pragma omp for
. In Ihrem Fall würde dies Folgendes bedeuten:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
ist semantisch und logisch dasselbe wie:
#pragma omp parallel
{
#pragma omp for
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
TL; DR: In Ihrem Beispiel wird #pragma omp parallel for
die Schleife zwischen den Threads parallelisiert ( dh die Schleifeniterationen werden zwischen den Threads aufgeteilt), während bei #pragma omp parallel
allen Threads alle Schleifeniterationen (parallel) ausgeführt werden .
Um es anschaulicher zu machen , würde mit 4
Threads das zu #pragma omp parallel
etwas führen wie:

wohingegen #pragma omp parallel for
mit a chunk_size=1
und a static schedule
etwas ergeben würde wie:

In Bezug auf den Code würde die Schleife in etwas umgewandelt, das logisch ähnlich ist wie:
for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{
c[i]=a[i]+b[i];
}
wo omp_get_thread_num ()
Die Routine omp_get_thread_num gibt die Thread-Nummer des aufrufenden Threads innerhalb des aktuellen Teams zurück.
und omp_get_num_threads ()
Gibt die Anzahl der Threads im aktuellen Team zurück. In einem sequentiellen Abschnitt des Programms gibt omp_get_num_threads 1 zurück.
oder mit anderen Worten , for(int i = THREAD_ID; i < n; i += TOTAL_THREADS)
. Mit THREAD_ID
Bereich von 0
bis TOTAL_THREADS - 1
und TOTAL_THREADS
Darstellung der Gesamtzahl der Threads des Teams, die in der parallelen Region erstellt wurden.
Ich habe gelernt, dass wir #pragma omp parallel verwenden müssen, während wir OpenMP in der for-Schleife verwenden. Aber ich habe das gleiche auch mit #pragma omp parallel versucht und es gibt mir auch die richtige Ausgabe.
Es gibt Ihnen die gleiche Ausgabe, weil in Ihrem Code:
c[i]=a[i]+b[i];
Array a
und Array b
werden nur gelesen, und Array c[i]
ist das einzige, das aktualisiert wird, und sein Wert hängt nicht davon ab, wie oft die Iteration i
ausgeführt wird. Trotzdem wird mit #pragma omp parallel for
jedem Thread sein eigenes aktualisiert i
, während mit #pragma omp parallel
Threads die gleichen i
s aktualisiert werden, wodurch die Werte des jeweils anderen überschrieben werden.
Versuchen Sie nun, dasselbe mit dem folgenden Code zu tun:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]= c[i] + a[i] + b[i];
}
}
und
#pragma omp for
{
for(int i=0;i<n;i++)
{
c[i] = c[i] + a[i] + b[i];
}
}
Sie werden den Unterschied sofort bemerken.
Im zweiten Fall ist die Schleife nicht parallelisiert. Die gesamte Schleife wird nämlich in jedem Thread ausgeführt . Im Allgemeinen wird alles, was sich innerhalb des parallelen Bereichs befindet, von allen Threads ausgeführt.
Sie können die Schleife im bereits vorhandenen Parallelbereich zusätzlich wie folgt parallelisieren:
#pragma omp parallel
{
#pragma omp for
for (int i = 0; i < n; i++)
c[i] = a[i] + b[i];
}