Différence entre #pragma omp parallel et #pragma omp parallel pour

Dec 11 2020

Je suis nouveau OpenMPet 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

5 dreamcrash Dec 11 2020 at 15:14

le

#pragma omp parallel:

créera un parallel regionavec une équipe de threads, où chaque thread exécutera tout le bloc de code qu'il parallel regioncontient.

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 threadsde cette région les itérations de la boucle qu'elle englobe seront assignées, en utilisant le default chunk size, et le default schedulequi est typiquement static . Gardez à l'esprit, cependant, que les default scheduledifférentes applications concrètes de la OpenMPnorme 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 forest une combinaison du constructeur #pragma omp parallelavec #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 forla 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 4threads #pragma omp parallel, cela donnerait quelque chose comme:

alors #pragma omp parallel forqu'avec un chunk_size=1et 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_IDallant de 0à TOTAL_THREADS - 1et TOTAL_THREADSrepré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 aet array bsont uniquement lus, et array c[i]est le seul à être mis à jour, et sa valeur ne dépend pas du nombre d' iexécutions de l'itération . Néanmoins, avec #pragma omp parallel forchaque thread mettra à jour le sien i, alors que avec les #pragma omp parallelthreads mettra à jour les mêmes is, 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.

2 DanielLangr Dec 11 2020 at 15:16

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