Unterschied zwischen #pragma omp parallel und #pragma omp parallel für

Dec 11 2020

Ich bin neu in OpenMPund 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

5 dreamcrash Dec 11 2020 at 15:14

Das

#pragma omp parallel::

erstellt ein parallel regionmit 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 threadsvon diesem Bereich werden die Iterationen der Schleife, die es einschließt, unter Verwendung des default chunk sizeund des, default scheduledas typischerweise ist , zugewiesen static. Beachten Sie jedoch, dass sich die default scheduleUnterschiede zwischen den verschiedenen konkreten Implementierungen des OpenMPStandards 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 forist eine Kombination des Konstruktors #pragma omp parallelmit #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 fordie 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 4Threads das zu #pragma omp paralleletwas führen wie:

wohingegen #pragma omp parallel formit a chunk_size=1und 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_IDBereich von 0bis TOTAL_THREADS - 1und TOTAL_THREADSDarstellung 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 aund Array bwerden nur gelesen, und Array c[i]ist das einzige, das aktualisiert wird, und sein Wert hängt nicht davon ab, wie oft die Iteration iausgeführt wird. Trotzdem wird mit #pragma omp parallel forjedem Thread sein eigenes aktualisiert i, während mit #pragma omp parallelThreads die gleichen is 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.

2 DanielLangr Dec 11 2020 at 15:16

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];
}