Recherche…


Paramètres

Clause Paramètre
private Liste de variables privées séparées par des virgules
firstprivate Comme private , mais initialisé à la valeur de la variable avant d'entrer dans la boucle
lastprivate Comme private , mais la variable obtiendra la valeur correspondant à la dernière itération de la boucle à la sortie
reduction Opérateur de réduction : liste séparée par des virgules des variables de réduction correspondantes
schedule static , dynamic , guided , auto ou runtime avec une taille de morceau optionnelle après un coma pour les 3 anciens
collapse Nombre de boucles parfaitement imbriquées à réduire et à paralléliser ensemble
ordered Indique que certaines parties de la boucle devront être conservées dans l'ordre (ces parties seront spécifiquement identifiées avec des clauses ordered dans le corps de la boucle)
nowait Supprimer la barrière implicite existante par défaut à la fin de la construction de boucle

Remarques

La signification de la clause d' schedule est la suivante:

  • static[,chunk] : distribue statiquement (c'est-à-dire que la distribution est effectuée avant d'entrer dans la boucle) les itérations de boucle en lots de taille de chunk dans un tour de rôle. Si chunk n'est pas spécifié, alors les morceaux sont aussi uniformes que possible et chaque thread obtient au plus un d'entre eux.
  • dynamic[,chunk] : distribuez les itérations de boucle entre les threads par lots de taille de chunk avec une chunk premier arrivé, premier servi, jusqu'à ce qu'il ne reste aucun lot. S'il n'est pas spécifié, le chunk est défini sur 1
  • guided[,chunk] : comme dynamic mais avec des lots dont les tailles deviennent de plus en plus petites, jusqu'à 1
  • auto : laisser le compilateur et / ou la bibliothèque d'exécution décider de ce qui convient le mieux
  • runtime : Reportez la décision à l'exécution au moyen de la variable d'environnement OMP_SCHEDULE . Si, au moment de l'exécution, la variable d'environnement n'est pas définie, la planification par défaut sera utilisée

La valeur par défaut pour la schedule est définie par l'implémentation . Dans de nombreux environnements, il est static , mais peut également être dynamic ou pourrait très bien être auto . Par conséquent, veillez à ce que votre implémentation ne repose pas implicitement sur elle sans la définir explicitement.

Dans les exemples ci-dessus, nous avons utilisé la forme fusionnée parallel for ou parallel do . Cependant, la construction de boucle peut être utilisée sans la fusionner avec la directive parallel , sous la forme d'une #pragma omp for [...] ou !$omp do [...] autonome dans une région parallel .

Pour la version Fortran uniquement, la ou les variables d'index de boucle de la ou des boucles parallèles sont toujours private par défaut. Il n'est donc pas nécessaire de les déclarer explicitement private (bien que cela ne soit pas une erreur).
Pour les versions C et C ++, les index de boucle sont comme les autres variables. Par conséquent, si leur étendue s'étend en dehors de la ou des boucles parallélisées (c'est-à-dire si elles ne sont pas déclarées comme for ( int i = ...) mais plutôt comme int i; ... for ( i = ... ) alors elles doivent être déclarés private .

Exemple typique en 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;
}

Dans cet exemple, nous calculons simplement 1 million de cosinus et additionnons leurs valeurs en parallèle. Nous chronométrons également l'exécution pour voir si la parallélisation a un effet sur les performances. Enfin, comme nous mesurons le temps, nous devons nous assurer que le compilateur n'optimisera pas le travail que nous avons effectué, donc nous faisons semblant d’utiliser le résultat en le retournant.

Même exemple à 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

Ici encore, nous calculons et accumulons 1 million de cosinus. Nous chronométrons la boucle et pour éviter toute optimisation indésirable du compilateur, nous faisons semblant d'utiliser le résultat.

Compiler et exécuter les exemples

Sur une machine Linux à 8 cœurs utilisant GCC version 4.4, les codes C peuvent être compilés et exécutés de la manière suivante:

$ 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

Pour la version Fortran, cela donne:

$ 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

Ajout de deux vecteurs en utilisant OpenMP parallèle pour construire

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

Cet exemple ajoute deux vecteurs ( A et B dans C ) en générant une équipe de threads (spécifiés par la variable d' OMP_NUM_THREADS OMP_NUM_THREADS, par exemple) et en attribuant à chaque thread un morceau de travail (dans cet exemple, assigné statiquement à la schedule(static) expression).

Voir la section des remarques concernant le caractère facultatif private(i) .



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow