Diferencia entre #pragma omp paralelo y #pragma omp paralelo para
Soy nuevo OpenMP
y he intentado ejecutar un programa que agrega dos matrices usando OpenMP. En el tutorial de OpenMP, aprendí que necesitamos usar #pragma omp paralelo mientras usamos OpenMP en el bucle for . Pero también he intentado lo mismo con #pragma omp paralelo y también me está dando el resultado correcto. A continuación se muestran los fragmentos de código de lo que estoy tratando de transmitir.
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
y
#pragma omp parallel
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
¿Cuál es la diferencia entre estos dos?
Respuestas
los
#pragma omp parallel
:
creará un parallel region
con un equipo de threads
, donde cada hilo ejecutará todo el bloque de código que parallel region
encierra.
Desde OpenMP 5.1 se puede leer una descripción más formal:
Cuando un hilo encuentra una construcción paralela , se crea un equipo de hilos para ejecutar la región paralela (..). El hilo que encontró la construcción paralela se convierte en el hilo principal del nuevo equipo, con un número de hilo de cero durante la duración de la nueva región paralela. Todos los hilos del nuevo equipo, incluido el hilo principal, ejecutan la región. Una vez que se crea el equipo, el número de subprocesos en el equipo permanece constante durante la duración de esa región paralela.
Los:
#pragma omp parallel for
creará un parallel region
(como se describió anteriormente), y al threads
de esa región se asignarán las iteraciones del bucle que encierra, utilizando el default chunk size
, y el default schedule
que normalmente es static
. Sin embargo, default schedule
tenga en cuenta que pueden diferir entre diferentes implementaciones concretas de la OpenMP
norma.
Desde OpenMP 5.1 puede leer una descripción más formal:
La construcción de bucle de trabajo compartido especifica que las iteraciones de uno o más bucles asociados se ejecutarán en paralelo por los subprocesos del equipo en el contexto de sus tareas implícitas. Las iteraciones se distribuyen entre los subprocesos que ya existen en el equipo que está ejecutando la región paralela a la que se une la región del ciclo de trabajo compartido .
Además ,
La construcción de bucle paralelo es un atajo para especificar una construcción en paralelo que contiene una construcción de bucle con uno o más bucles asociados y ninguna otra declaración.
O informalmente, #pragma omp parallel for
es una combinación del constructor #pragma omp parallel
con #pragma omp for
. En su caso, esto significaría que:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
es semántica y lógicamente lo mismo que:
#pragma omp parallel
{
#pragma omp for
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
TL; DR: En su ejemplo, con #pragma omp parallel for
el bucle se paralelizará entre los hilos ( es decir, las iteraciones del bucle se dividirán entre los hilos), mientras que con #pragma omp parallel
todos los hilos se ejecutarán (en paralelo) todas las iteraciones del bucle.
Para hacerlo más ilustrativo, con 4
hilos el #pragma omp parallel
, resultaría en algo como:

mientras que #pragma omp parallel for
con una chunk_size=1
y una estática schedule
resultaría en algo como:

En cuanto al código, el bucle se transformaría en algo lógicamente similar a:
for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{
c[i]=a[i]+b[i];
}
donde omp_get_thread_num ()
La rutina omp_get_thread_num devuelve el número de hilo, dentro del equipo actual, del hilo de llamada.
y omp_get_num_threads ()
Devuelve el número de subprocesos del equipo actual. En una sección secuencial del programa omp_get_num_threads devuelve 1.
o en otras palabras, for(int i = THREAD_ID; i < n; i += TOTAL_THREADS)
. Con un THREAD_ID
rango de 0
hasta TOTAL_THREADS - 1
y TOTAL_THREADS
representando el número total de subprocesos del equipo creados en la región paralela.
Aprendí que necesitamos usar #pragma omp paralelo mientras usamos OpenMP en el ciclo for. Pero también he intentado lo mismo con #pragma omp paralelo y también me está dando el resultado correcto.
Te da el mismo resultado, porque en tu código:
c[i]=a[i]+b[i];
matriz a
y matriz b
solo se leen, y matriz c[i]
es la única que se actualiza, y su valor no depende de cuántas veces i
se ejecutará la iteración . Sin embargo, con #pragma omp parallel for
cada hilo se actualizará el suyo i
, mientras que con los #pragma omp parallel
hilos se actualizarán los mismos i
s, por lo que se anularán los valores de los demás.
Ahora intente hacer lo mismo con el siguiente código:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]= c[i] + a[i] + b[i];
}
}
y
#pragma omp for
{
for(int i=0;i<n;i++)
{
c[i] = c[i] + a[i] + b[i];
}
}
Inmediatamente notará la diferencia.
En el segundo caso, el bucle no está en paralelo. Es decir, el ciclo completo se ejecuta en cada hilo . Generalmente, lo que está dentro de la región paralela es ejecutado por todos los subprocesos.
Además, puede paralelizar el bucle en la región paralela ya existente de la siguiente manera:
#pragma omp parallel
{
#pragma omp for
for (int i = 0; i < n; i++)
c[i] = a[i] + b[i];
}