2017-11-25 1 views
0

Ich bin relativ neu zu OpenMP und ich habe einige Monte-Carlo-Code, den ich parallelisieren möchte.OpenMP - Overhead beim Erstellen und Beenden von Threads in der For-Schleife

Ich habe eine for-Schleife, die in Reihe lief werden müssen, die die new_value() Funktion aufruft:

for(int i = 0; i < MAX_VAL; i++) 
    new_value(); 

Diese Funktion bei jedem Aufruf einer parallelen Region öffnet:

void new_value() 
{ 
#pragma omp parallel default(shared) 
{ 
    int thread_rank = omp_get_thread_num(); 

#pragma omp for schedule(static) 
    for(int i = 0; i < N; i++) 
     arr[i] = update(thread_rank); 
} 
} 

Welche funktioniert, aber es gibt eine erhebliche Menge an Overhead, der mit dem Laichen und dem Beenden von Threads verbunden ist; Ich fragte mich, ob jemand einen Weg kannte, die Threads zu spawnen (und thread_rank zu erreichen), bevor er die Schleife betrat, ohne die Schleife zu parallelisieren?

Es gibt einige Fragen, die gleiche Sache zu fragen, aber sie sind entweder falsch oder unbeantwortet, wobei Beispiele dafür:

This question, die fragt eine ähnliche Sache und die Antwort schlägt eine parallele Region zu schaffen und dann #pragma omp single mit auf die äußerste Schleife, aber wie 'Joe C' in den Antwortkommentaren sagte, funktioniert das nicht. Ich kann bestätigen, dass das Programm gerade hängt.

This question fragt die genaue Gleiche, aber die (unticked) Antwort ist nur die äußerste Schleife parallelisieren die Schleife 4000 * num_threads läuft die weder, was die Fragesteller wollten noch was ich will.

Antwort

0

Die Antwort auf Ihre zweite Frage ist eigentlich richtig.

#pragma omp parallel 
for(int i = 0; i < MAX_VAL; i++) 
    new_value(); 

void new_value() 
{ 
    int thread_rank = omp_get_thread_num(); 

#pragma omp for schedule(static) 
    for(int i = 0; i < N; i++) 
     arr[i] = update(thread_rank); 
} 

Ist richtig und genau das, was Sie wollen. Es hat dieselbe Semantik wie der Code in Ihrer Frage. Der Unterschied besteht darin, dass es nur einen parallelen Bereich gibt und dass die Schleifenvariable i jetzt vom gesamten Team berechnet wird. Beachten Sie, dass die äußere Schleife nicht in einer Worksharing-Art parallelisiert ist (omp parallel for). So

wenn dieser Code ausgeführt wird, wird num_threads Threads ausführen den Schleifenkopf einmal new_value und erreichen die omp for alle mit ihren privaten i == 0. Sie werden die Arbeit der inneren Schleife teilen. Dann werden sie warten, bis alle die Schleife an einer impliziten Barriere abgeschlossen haben, inkrementieren ihre private i und wiederholen ... Ich hoffe, es ist jetzt klar, dass dies das gleiche Verhalten in Bezug auf die innere Schleife wie zuvor ist, mit weniger Thread-Verwaltungsaufwand.

+0

Das macht sehr viel Sinn, danke für die tolle Erklärung. Ich habe eine kleine Folgefrage (wenn es Ihnen nichts ausmacht): Wie würde ich jeden Thread dazu bringen, die for-Schleife in der Art und Weise auszuführen, wie ich ursprünglich dachte, d. H. 'Num_threads * MAX_VAL' mal? – BodneyC

+0

Tatsächlich wird 'num_threads * MAX_VAL' ausgeführt, aber aufgrund der Worksharing-Operation wird die innere Schleifeniteration nur' MAX_VAL * N' mal ausgeführt. Daher würde das Entfernen des inneren "omp for" zu einer solchen Ausführung führen, bei der der innere Schleifenkörper "num_threads * MAX_VAL * N" mal ausgeführt wird. – Zulan

+0

Spot on, das macht Sinn. Danke noch einmal. – BodneyC

Verwandte Themen