Différence entre #pragma omp parallel et #pragma omp parallel pour
Je suis nouveau OpenMP
et j'ai essayé d'exécuter un programme qui ajoute deux tableaux en utilisant OpenMP. Dans le didacticiel OpenMP, j'ai appris que nous devons utiliser #pragma omp parallel pour tout en utilisant OpenMP sur la boucle for . Mais j'ai aussi essayé la même chose avec #pragma omp parallel et cela me donne également la sortie correcte. Voici les extraits de code de ce que j'essaie de transmettre.
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
et
#pragma omp parallel
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
Quelle est la différence entre ces deux?
Réponses
le
#pragma omp parallel
:
créera un parallel region
avec une équipe de threads
, où chaque thread exécutera tout le bloc de code qu'il parallel region
contient.
Depuis OpenMP 5.1, on peut lire une description plus formelle:
Lorsqu'un thread rencontre une construction parallèle , une équipe de threads est créée pour exécuter la région parallèle (..). Le thread qui a rencontré la construction parallèle devient le thread principal de la nouvelle équipe, avec un numéro de thread de zéro pour la durée de la nouvelle région parallèle. Tous les threads de la nouvelle équipe, y compris le thread principal, exécutent la région. Une fois l'équipe créée, le nombre de threads dans l'équipe reste constant pendant toute la durée de cette région parallèle.
Le:
#pragma omp parallel for
créera un parallel region
(comme décrit précédemment), et à la threads
de cette région les itérations de la boucle qu'elle englobe seront assignées, en utilisant le default chunk size
, et le default schedule
qui est typiquement static
. Gardez à l'esprit, cependant, que les default schedule
différentes applications concrètes de la OpenMP
norme peuvent différer .
Depuis OpenMP 5.1, vous pouvez lire une description plus formelle:
La construction de boucle de partage de projet spécifie que les itérations d'une ou plusieurs boucles associées seront exécutées en parallèle par les threads de l'équipe dans le contexte de leurs tâches implicites. Les itérations sont réparties sur les threads qui existent déjà dans l'équipe qui exécute la région parallèle à laquelle la région de boucle de partage de projet se lie .
De plus ,
La construction de boucle parallèle est un raccourci pour spécifier une construction parallèle contenant une construction de boucle avec une ou plusieurs boucles associées et aucune autre instruction.
Ou de manière informelle, #pragma omp parallel for
est une combinaison du constructeur #pragma omp parallel
avec #pragma omp for
. Dans votre cas, cela signifierait que:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
est sémantiquement et logiquement identique à:
#pragma omp parallel
{
#pragma omp for
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
TL; DR: Dans votre exemple, avec #pragma omp parallel for
la boucle sera parallélisé entre les threads ( c'est-à-dire que les itérations de la boucle seront divisées entre les threads), alors qu'avec #pragma omp parallel
tous les threads exécutera (en parallèle) toutes les itérations de la boucle.
Pour le rendre plus illustratif, avec des 4
threads #pragma omp parallel
, cela donnerait quelque chose comme:

alors #pragma omp parallel for
qu'avec un chunk_size=1
et un statique, cela schedule
donnerait quelque chose comme:

Au niveau du code, la boucle serait transformée en quelque chose de logiquement similaire à:
for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{
c[i]=a[i]+b[i];
}
où omp_get_thread_num ()
La routine omp_get_thread_num renvoie le numéro de thread, au sein de l'équipe en cours, du thread appelant.
et omp_get_num_threads ()
Renvoie le nombre de threads dans l'équipe actuelle. Dans une section séquentielle du programme, omp_get_num_threads renvoie 1.
autrement dit, for(int i = THREAD_ID; i < n; i += TOTAL_THREADS)
. Avec THREAD_ID
allant de 0
à TOTAL_THREADS - 1
et TOTAL_THREADS
représentant le nombre total de threads de l'équipe créés sur la région parallèle.
J'ai appris que nous devons utiliser #pragma omp parallel pour tout en utilisant OpenMP sur la boucle for. Mais j'ai aussi essayé la même chose avec #pragma omp parallel et cela me donne également la sortie correcte.
Cela vous donne le même résultat, car dans votre code:
c[i]=a[i]+b[i];
array a
et array b
sont uniquement lus, et array c[i]
est le seul à être mis à jour, et sa valeur ne dépend pas du nombre d' i
exécutions de l'itération . Néanmoins, avec #pragma omp parallel for
chaque thread mettra à jour le sien i
, alors que avec les #pragma omp parallel
threads mettra à jour les mêmes i
s, remplaçant ainsi les valeurs des autres.
Maintenant, essayez de faire de même avec le code suivant:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]= c[i] + a[i] + b[i];
}
}
et
#pragma omp for
{
for(int i=0;i<n;i++)
{
c[i] = c[i] + a[i] + b[i];
}
}
vous remarquerez immédiatement la différence.
Dans le second cas, la boucle n'est pas parallélisée. À savoir, la boucle entière est exécutée dans chaque thread . En général, tout ce qui se trouve à l'intérieur de la région parallèle est exécuté par tous les threads.
Vous pouvez en outre paralléliser la boucle dans la région parallèle déjà existante comme suit:
#pragma omp parallel
{
#pragma omp for
for (int i = 0; i < n; i++)
c[i] = a[i] + b[i];
}