Suche…


Parameter

Klausel Parameter
private Kommagetrennte Liste der privaten Variablen
firstprivate Wie private , aber vor dem Eintritt in die Schleife auf den Wert der Variablen initialisiert
lastprivate Wie private , aber die Variable erhält den Wert, der der letzten Iteration der Schleife beim Beenden entspricht
reduction Reduktionsoperator : Kommas getrennte Liste der entsprechenden Reduktionsvariablen
schedule static , dynamic , guided , auto oder runtime mit einer optionalen Chunk-Größe nach dem Koma für den 3-Former
collapse Anzahl perfekt geschachtelter Schleifen zum Zusammenfallen und Parallelisieren
ordered Sagt, dass einige Teile der Schleife in der richtigen Reihenfolge gehalten werden müssen (diese Teile werden durch einige ordered Klauseln innerhalb des Schleifenkörpers spezifisch gekennzeichnet)
nowait Entfernen Sie die implizite Barriere, die standardmäßig am Ende des Schleifenkonstrukts vorhanden ist

Bemerkungen

Die Bedeutung der schedule Klausel lautet wie folgt:

  • static[,chunk] : Verteilen Sie statisch (dh die Verteilung erfolgt vor dem Eintritt in die Schleife) die Iterationen der Schleife in Batch- chunk Größe in einem Round-Robin-Verfahren. Wenn chunk nicht angegeben wird, sind die Chunks so gleichmäßig wie möglich und jeder Thread erhält höchstens einen von ihnen.
  • dynamic[,chunk] : Verteilen Sie die Loop-Iterationen unter den Threads nach Chargen der chunk mit einer First-Come-First-Served-Policy, bis keine Charge übrig bleibt. Wenn nicht angegeben, wird chunk auf 1 gesetzt
  • guided[,chunk] : Wie dynamic aber mit Chargen, deren Größen immer kleiner werden (bis 1)
  • auto : Lass den Compiler und / oder die Laufzeitbibliothek entscheiden, was am besten geeignet ist
  • runtime : Verschieben Sie die Entscheidung zur Laufzeit anhand der Umgebungsvariablen OMP_SCHEDULE . Wenn zur Laufzeit die Umgebungsvariable nicht definiert ist, wird die Standardplanung verwendet

Der Standard für den schedule ist die Implementierungsdefinition . In vielen Umgebungen ist es static , kann aber auch dynamic oder sehr wohl auto . Achten Sie daher darauf, dass Ihre Implementierung nicht implizit auf sie angewiesen ist, ohne sie explizit festzulegen.

In den obigen Beispielen haben wir die verschmolzene Form parallel for oder parallel do . Das Schleifenkonstrukt kann jedoch verwendet werden, ohne es mit der parallel Direktive in Form einer #pragma omp for [...] oder !$omp do [...] Standalone-Direktive innerhalb einer parallel Region zu !$omp do [...] .

Nur für die Fortran-Version ist (sind) die Schleifenindexvariable (n) der parallelisierten Schleifen standardmäßig immer private . Sie müssen daher nicht explizit als private deklariert werden (dies ist jedoch kein Fehler).
Für die C- und C ++ - Version sind die Schleifenindizes wie alle anderen Variablen. Wenn sich ihr Gültigkeitsbereich außerhalb der parallelisierten Schleife (s) erstreckt (dh, wenn sie nicht wie for ( int i = ...) sondern eher als int i; ... for ( i = ... ) deklariert sind int i; ... for ( i = ... ) dann sind sie dies müssen als private deklariert werden.

Typisches Beispiel in C

#include <stdio.h>
#include <math.h>
#include <omp.h>

#define N 1000000

int main() {
    double sum = 0;

    double tbegin = omp_get_wtime();
    #pragma omp parallel for reduction( +: sum )
    for ( int i = 0; i < N; i++ ) {
        sum += cos( i );
    }
    double wtime = omp_get_wtime() - tbegin;

    printf( "Computing %d cosines and summing them with %d threads took %fs\n",
            N, omp_get_max_threads(), wtime );

    return sum;
}

In diesem Beispiel berechnen wir nur 1 Million Cosinus und summieren ihre Werte parallel. Wir prüfen die Ausführung auch, um zu sehen, ob die Parallelisierung Auswirkungen auf die Leistung hat. Da wir die Zeit messen, müssen wir schließlich sicherstellen, dass der Compiler die von uns geleistete Arbeit nicht optimiert. Wir geben also vor, das Ergebnis zu verwenden, indem wir es zurückgeben.

Dasselbe Beispiel in Fortran

program typical_loop
    use omp_lib
    implicit none
    integer, parameter :: N = 1000000, kd = kind( 1.d0 )
    real( kind = kd ) :: sum, tbegin, wtime
    integer :: i

    sum = 0

    tbegin = omp_get_wtime()
    !$omp parallel do reduction( +: sum )
    do i = 1, N
        sum = sum + cos( 1.d0 * i )
    end do
    !$omp end parallel do
    wtime = omp_get_wtime() - tbegin

    print "( 'Computing ', i7, ' cosines and summing them with ', i2, &
        & ' threads took ', f6.4,'s' )", N, omp_get_max_threads(), wtime

    if ( sum > N ) then
        print *, "we only pretend using sum"
    end if
end program typical_loop

Hier berechnen und berechnen wir erneut 1 Million Cosinus. Wir setzen die Schleife zeitlich fest, und um unerwünschte Compiler-Optimierungen zu vermeiden, geben wir vor, das Ergebnis zu verwenden.

Beispiele kompilieren und ausführen

Auf einem 8-Cores-Linux-Computer mit GCC-Version 4.4 können die C-Codes folgendermaßen kompiliert und ausgeführt werden:

$ gcc -std=c99 -O3 -fopenmp loop.c -o loopc -lm
$ OMP_NUM_THREADS=1 ./loopc
Computing 1000000 cosines and summing them with 1 threads took 0.095832s
$ OMP_NUM_THREADS=2 ./loopc
Computing 1000000 cosines and summing them with 2 threads took 0.047637s
$ OMP_NUM_THREADS=4 ./loopc
Computing 1000000 cosines and summing them with 4 threads took 0.024498s
$ OMP_NUM_THREADS=8 ./loopc
Computing 1000000 cosines and summing them with 8 threads took 0.011785s

Für die Fortran-Version gibt es:

$ gfortran -O3 -fopenmp loop.f90 -o loopf
$ OMP_NUM_THREADS=1 ./loopf
Computing 1000000 cosines and summing them with  1 threads took 0.0915s
$ OMP_NUM_THREADS=2 ./loopf
Computing 1000000 cosines and summing them with  2 threads took 0.0472s
$ OMP_NUM_THREADS=4 ./loopf
Computing 1000000 cosines and summing them with  4 threads took 0.0236s
$ OMP_NUM_THREADS=8 ./loopf
Computing 1000000 cosines and summing them with  8 threads took 0.0118s

Addition zweier Vektoren mit OpenMP parallel zum Konstrukt

void parallelAddition (unsigned N, const double *A, const double *B, double *C)
{
    unsigned i;

    #pragma omp parallel for shared (A,B,C,N) private(i) schedule(static)
    for (i = 0; i < N; ++i)
    {
        C[i] = A[i] + B[i];
    }
}

In diesem Beispiel werden zwei Vektoren ( A und B in C ) eingefügt, indem ein Team von Threads (z. B. durch die OMP_NUM_THREADS OMP_NUM_THREADS angegeben OMP_NUM_THREADS aufgerufen wird und jedem Thread ein Arbeitsblock zugewiesen wird (in diesem Beispiel statisch durch den schedule(static) zugewiesen Ausdruck).

Siehe Abschnitt "Anmerkungen" bezüglich der private(i) Wahlmöglichkeit.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow