omp parallel vs. omp parallel für

105

Was ist der Unterschied zwischen diesen beiden?

[EIN]

#pragma omp parallel
{ 
    #pragma omp for
    for(int i = 1; i < 100; ++i)
    {
        ...
    }
}

[B]

#pragma omp parallel for
for(int i = 1; i < 100; ++i)
{
   ...
}
Hyunjik Bae
quelle

Antworten:

65

Ich glaube nicht, dass es einen Unterschied gibt, einer ist eine Abkürzung für den anderen. Obwohl Ihre genaue Implementierung möglicherweise anders damit umgeht.

Die kombinierten parallelen Worksharing-Konstrukte sind eine Verknüpfung zum Angeben eines parallelen Konstrukts, das ein Worksharing-Konstrukt und keine anderen Anweisungen enthält. Zulässige Klauseln sind die Vereinigung der Klauseln, die für die Parallel- und Worksharing-Konstruktionen zulässig sind.

Entnommen aus http://www.openmp.org/mp-documents/OpenMP3.0-SummarySpec.pdf

Die Spezifikationen für OpenMP finden Sie hier:

https://openmp.org/specifications/

Ade Miller
quelle
66

Diese sind gleichwertig.

#pragma omp parallelerzeugt eine Gruppe von Threads, während #pragma omp forSchleifeniterationen zwischen den erzeugten Threads aufgeteilt werden. Mit der fusionierten #pragma omp parallel forDirektive können Sie beide Dinge gleichzeitig tun .

Krzysztof Kosiński
quelle
In meinem Code verwende ich genau diese Struktur. Wenn ich jedoch die schedule(static, chunk)Klausel in der Direktive verwende, tritt ein Problem auf. Der Code läuft gut, aber wenn ich diesen Code von einem MPI-Programm aus aufrufe, läuft er in eine Endlosschleife. Der Schleifenzähler ist in allen Iterationen dieser Schleife Null. Ich habe den Schleifenzähler in der #pragma omp parallelDirektive als privat definiert . Keine Ahnung, warum es nur fehlschlägt, wenn MPI den Code aufruft. Ich bin mir ziemlich sicher, dass jeder MPI-Prozess auf einem anderen Prozessor des Clusters ausgeführt wird, wenn dies wichtig ist. Keine Ahnung, ob der Zeitplan das Problem verursacht.
Rohit Banga
Das gleiche funktioniert gut, wenn ich die #pragma omp parallel forDirektive verwende. Es sollte einen Unterschied geben.
Rohit Banga
1
Update: Wie sich herausstellt, beobachte ich dieses Problem nur, wenn ich die Schedule-Klausel verwende. Ich denke, es hängt nicht davon ab, ob ich die kombinierte Parallele für oder zwei verschiedene Direktiven verwende.
Rohit Banga
28

Hier ist ein Beispiel für die Verwendung von getrennt parallelund for hier . Kurz gesagt, es kann für die dynamische Zuweisung von OpenMP-Thread-Private-Arrays verwendet werden, bevor der forZyklus in mehreren Threads ausgeführt wird. Es ist unmöglich, die gleiche Initialisierung für den parallel forFall durchzuführen .

UPD: Im Fragenbeispiel gibt es keinen Unterschied zwischen einem einzelnen Pragma und zwei Pragmas. In der Praxis können Sie jedoch mit getrennten parallelen und für Direktiven ein Thread-bewussteres Verhalten erzielen. Ein Code zum Beispiel:

#pragma omp parallel
{ 
    double *data = (double*)malloc(...); // this data is thread private

    #pragma omp for
    for(1...100) // first parallelized cycle
    {
    }

    #pragma omp single 
    {} // make some single thread processing

    #pragma omp for // second parallelized cycle
    for(1...100)
    {
    }

    #pragma omp single 
    {} // make some single thread processing again

    free(data); // free thread private data
}
NtsDK
quelle
9

Obwohl beide Versionen des spezifischen Beispiels gleichwertig sind, wie bereits in den anderen Antworten erwähnt, gibt es immer noch einen kleinen Unterschied zwischen ihnen. Die erste Version enthält eine unnötige implizite Barriere, die am Ende des "omp for" auftritt. Die andere implizite Barriere befindet sich am Ende des Parallelbereichs. Durch Hinzufügen von "nowait" zu "omp for" würden die beiden Codes zumindest aus OpenMP-Sicht gleichwertig. Ich erwähne dies, weil ein OpenMP-Compiler für beide Fälle leicht unterschiedlichen Code generieren könnte.

Phadjido
quelle
7

Ich sehe ganz andere Laufzeiten, wenn ich in g ++ 4.7.0 eine for-Schleife nehme und benutze

std::vector<double> x;
std::vector<double> y;
std::vector<double> prod;

for (int i = 0; i < 5000000; i++)
{
   double r1 = ((double)rand() / double(RAND_MAX)) * 5;
   double r2 = ((double)rand() / double(RAND_MAX)) * 5;
   x.push_back(r1);
   y.push_back(r2);
}

int sz = x.size();

#pragma omp parallel for

for (int i = 0; i< sz; i++)
   prod[i] = x[i] * y[i];

Der Seriencode (nein openmp) läuft in 79 ms. Der Code "Parallel für" läuft in 29 ms. Wenn ich das weglasse forund benutze #pragma omp parallel, schießt die Laufzeit bis zu 179 ms, was langsamer als der Seriencode ist. (Die Maschine hat eine Hardware-Parallelität von 8)

Der Code verlinkt auf libgomp

parcompute
quelle
2
Ich denke, das liegt daran, dass omp parallel eine Schleife in einem separaten Thread ausführt, ohne sie in Threads zu unterteilen. Der Haupt-Thread wartet also darauf, dass der zweite Thread fertig ist. und die Zeit wird für die Synchronisierung aufgewendet.
Antigluk
7
Das liegt daran, dass es ohne a überhaupt #pragma omp forkeine Multithread-gemeinsame Nutzung der Schleife gibt. Aber das war sowieso nicht der Fall der OPs. Versuchen Sie es erneut mit einem zusätzlichen im #pragma omp forInneren #pragm omp parallelund es sollte ähnlich (wenn nicht gleich) wie die #pragma omp parallel forVersion laufen .
Christian Rau
2
Ich sehe diese Antwort als die beste an, da sie zeigt, dass sie nicht "gleichwertig" sind
gescheiterter Wissenschaftler
6

Es gibt offensichtlich viele Antworten, aber diese beantwortet es sehr gut (mit Quelle)

#pragma omp fordelegiert nur Teile der Schleife für verschiedene Threads im aktuellen Team. Ein Team ist die Gruppe von Threads, die das Programm ausführen. Zu Beginn des Programms besteht das Team nur aus einem einzigen Mitglied: dem Master-Thread , der das Programm ausführt.

Um ein neues Thread-Team zu erstellen, müssen Sie das parallele Schlüsselwort angeben. Es kann im umgebenden Kontext angegeben werden:

#pragma omp parallel
{
   #pragma omp for
   for(int n = 0; n < 10; ++n)
   printf(" %d", n);
}

und:

Was sind: parallel, für und ein Team

Der Unterschied zwischen parallel, parallel für und für ist wie folgt:

Ein Team ist die Gruppe von Threads, die derzeit ausgeführt werden. Zu Beginn des Programms besteht das Team aus einem einzigen Thread. Ein paralleles Konstrukt teilt den aktuellen Thread für die Dauer des nächsten Blocks / der nächsten Anweisung in ein neues Thread-Team auf. Danach wird das Team wieder zu einem zusammengeführt. for teilt die Arbeit der for-Schleife auf die Threads des aktuellen Teams auf.

Es werden keine Threads erstellt, sondern nur die Arbeit auf die Threads des aktuell ausgeführten Teams aufgeteilt. parallel für ist eine Abkürzung für zwei Befehle gleichzeitig: parallel und für. Parallel erstellt ein neues Team und teilt dieses Team auf, um verschiedene Teile der Schleife zu verarbeiten. Wenn Ihr Programm niemals ein paralleles Konstrukt enthält, gibt es nie mehr als einen Thread. Der Master-Thread, der das Programm startet und ausführt, wie in Nicht-Threading-Programmen.

https://bisqwit.iki.fi/story/howto/openmp/

fogx
quelle