Buscar..


Parámetros

Cláusula Parámetro
private Lista de variables privadas separadas por comas
firstprivate Como private , pero inicializado con el valor de la variable antes de ingresar al bucle
lastprivate Como private , pero la variable obtendrá el valor correspondiente a la última iteración del bucle al salir
reduction operador de reducción : lista separada por comas de las variables de reducción correspondientes
schedule static , dynamic , guided , auto o en runtime con un tamaño de fragmento opcional después de un coma para los 3 primeros
collapse Número de bucles perfectamente anidados para colapsar y paralelizar juntos
ordered Indica que algunas partes del bucle deberán mantenerse en orden (estas partes se identificarán específicamente con algunas cláusulas ordered dentro del cuerpo del bucle)
nowait Elimine la barrera implícita existente de forma predeterminada al final de la construcción del bucle

Observaciones

El significado de la cláusula de schedule es el siguiente:

  • static[,chunk] : distribuye estáticamente (lo que significa que la distribución se realiza antes de ingresar al bucle) las iteraciones de bucle en lotes de tamaño de chunk de forma rotatoria. Si no se especifica el chunk , entonces los trozos son lo más parejos posible y cada hilo obtiene como máximo uno de ellos.
  • dynamic[,chunk] : distribuye las iteraciones de bucle entre los hilos por lotes de tamaño de chunk con una política de primer orden de llegada, hasta que no quede ningún lote. Si no se especifica, el chunk se establece en 1
  • guided[,chunk] : como dynamic pero con lotes cuyos tamaños se hacen cada vez más pequeños, hasta 1
  • auto : deje que el compilador y / o la biblioteca de tiempo de ejecución decidan cuál es la más adecuada
  • runtime : difiera la decisión en tiempo de ejecución mediante la variable de entorno OMP_SCHEDULE . Si en el tiempo de ejecución la variable de entorno no está definida, se utilizará la programación predeterminada

El valor predeterminado para la schedule es la implementación definida . En muchos entornos es static , pero también puede ser dynamic o bien podría ser auto . Por lo tanto, tenga cuidado de que su implementación no dependa implícitamente de ella sin establecerla explícitamente.

En los ejemplos anteriores, utilizamos la forma fusionada parallel for o parallel do . Sin embargo, la construcción de bucle se puede usar sin fusionarla con la directiva parallel , en forma de #pragma omp for [...] o !$omp do [...] directiva independiente dentro de una región parallel .

Solo para la versión de Fortran, las variables de índice de bucle del (de los) bucle (s) paralizado (es) son siempre private por defecto. Por lo tanto, no hay necesidad de declararlos explícitamente como private (aunque hacerlo no es un error).
Para la versión C y C ++, los índices de bucle son como cualquier otra variable. Por lo tanto, si su alcance se extiende fuera del (los) bucle (s) paralelizado (es decir, si no se declaran como for ( int i = ...) sino como int i; ... for ( i = ... ) entonces Tienen que ser declarados private .

Ejemplo típico 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;
}

En este ejemplo, solo calculamos 1 millón de cosenos y sumamos sus valores en paralelo. También cronometramos la ejecución para ver si la paralelización tiene algún efecto en el rendimiento. Finalmente, ya que medimos el tiempo, debemos asegurarnos de que el compilador no optimizará el trabajo que hemos realizado, por lo que pretendemos usar el resultado simplemente devolviéndolo.

Mismo ejemplo en 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

Aquí nuevamente calculamos y acumulamos 1 millón de cosenos. Calculamos el bucle y, para evitar la optimización del compilador no deseado, se pretende utilizar el resultado.

Compilando y ejecutando los ejemplos.

En una máquina Linux de 8 cores que usa GCC versión 4.4, los códigos C se pueden compilar y ejecutar de la siguiente manera:

$ 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

Para la versión Fortran, da:

$ 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

Adición de dos vectores usando OpenMP paralelo para la construcción

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

Este ejemplo agrega dos vectores ( A y B en C ) generando un equipo de subprocesos (especificados por la variable de OMP_NUM_THREADS OMP_NUM_THREADS, por ejemplo) y asignando a cada subproceso una parte del trabajo (en este ejemplo, asignado de forma estática a través de la schedule(static) expresión).

Ver la sección de comentarios con respecto a la opcionalidad private(i) .



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow