Differenza tra #pragma omp parallel e #pragma omp parallel for

Dec 11 2020

Sono nuovo OpenMPe ho provato a eseguire un programma che aggiunge due array utilizzando OpenMP. Nel tutorial di OpenMP, ho imparato che dobbiamo usare #pragma omp parallel per mentre si usa OpenMP sul ciclo for . Ma ho anche provato la stessa cosa con #pragma omp parallel e mi sta anche dando l'output corretto. Di seguito sono riportati gli snippet di codice di ciò che sto cercando di trasmettere.

#pragma omp parallel for
{
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}

e

 #pragma omp parallel
{
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}

Qual è la differenza tra questi due?

Risposte

5 dreamcrash Dec 11 2020 at 15:14

Il

#pragma omp parallel:

creerà un parallel regioncon un team di threads, dove ogni thread eseguirà l'intero blocco di codice che parallel regionracchiude.

Da OpenMP 5.1 si può leggere una descrizione più formale:

Quando un thread incontra un costrutto parallelo , viene creato un team di thread per eseguire la regione parallela (..). Il thread che ha incontrato il costrutto parallelo diventa il thread principale del nuovo team, con un numero di thread pari a zero per la durata della nuova regione parallela. Tutti i thread nel nuovo team, incluso il thread principale, eseguono la regione. Una volta creato il team, il numero di thread nel team rimane costante per la durata di quella regione parallela.

Il:

#pragma omp parallel for

creerà un parallel region(come descritto prima), e al threadsdi quella regione verranno assegnate le iterazioni del ciclo che racchiude, usando il default chunk size, e il default scheduleche è tipicamente static . Tenere presente, tuttavia, che default schedulepotrebbero differire tra le diverse implementazioni concrete dello OpenMPstandard.

Da OpenMP 5.1 puoi leggere una descrizione più formale:

Il costrutto del ciclo di condivisione del lavoro specifica che le iterazioni di uno o più cicli associati verranno eseguite in parallelo dai thread nel team nel contesto delle loro attività implicite. Le iterazioni vengono distribuite tra i thread già esistenti nel team che esegue la regione parallela a cui si lega la regione del ciclo di condivisione del lavoro .

Inoltre ,

Il costrutto di ciclo parallelo è una scorciatoia per specificare un costrutto parallelo contenente un costrutto di ciclo con uno o più cicli associati e nessun'altra istruzione.

O informalmente, #pragma omp parallel forè una combinazione del costruttore #pragma omp parallelcon #pragma omp for. Nel tuo caso, ciò significherebbe che:

#pragma omp parallel for
{
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}

è semanticamente e logicamente lo stesso di:

#pragma omp parallel
{
      #pragma omp for
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}

TL; DR: Nel tuo esempio, con #pragma omp parallel foril ciclo verrà parallelizzato tra i thread ( cioè, le iterazioni del ciclo saranno divise tra i thread), mentre con #pragma omp parallel tutti i thread verranno eseguite (in parallelo) tutte le iterazioni del ciclo.

Per renderlo più illustrativo, con i 4thread #pragma omp parallel, si otterrebbe qualcosa come:

mentre #pragma omp parallel forcon a chunk_size=1e statico si schedule otterrebbe qualcosa di simile:

Dal punto di vista del codice, il ciclo verrebbe trasformato in qualcosa di logicamente simile a:

for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{  
    c[i]=a[i]+b[i];
}

dove omp_get_thread_num ()

La routine omp_get_thread_num restituisce il numero di thread, all'interno del team corrente, del thread chiamante.

e omp_get_num_threads ()

Restituisce il numero di thread nel team corrente. In una sezione sequenziale del programma omp_get_num_threads restituisce 1.

o in altre parole, for(int i = THREAD_ID; i < n; i += TOTAL_THREADS). Con THREAD_IDche vanno da 0a TOTAL_THREADS - 1e che TOTAL_THREADSrappresentano il numero totale di thread del team creato nella regione parallela.

Ho imparato che dobbiamo usare #pragma omp parallel per mentre si usa OpenMP sul ciclo for. Ma ho anche provato la stessa cosa con #pragma omp parallel e mi sta anche dando l'output corretto.

Ti dà lo stesso output, perché nel tuo codice:

 c[i]=a[i]+b[i];

array ae array bvengono solo letti e array c[i]è l'unico che viene aggiornato e il suo valore non dipende da quante volte iverrà eseguita l'iterazione . Tuttavia, con #pragma omp parallel forogni thread aggiornerà il proprio i, mentre con i #pragma omp parallelthread aggiornerà gli stessi i, quindi sovrascrivendo i valori a vicenda.

Ora prova a fare lo stesso con il codice seguente:

#pragma omp parallel for
{
      for(int i=0;i<n;i++)
       {  
            c[i]= c[i] + a[i] + b[i];
       }
}

e

#pragma omp for
{
      for(int i=0;i<n;i++)
       {  
            c[i] = c[i] + a[i] + b[i];
       }
}

noterai subito la differenza.

2 DanielLangr Dec 11 2020 at 15:16

Nel secondo caso, il ciclo non è parallelizzato. Vale a dire, l' intero ciclo viene eseguito in ogni thread . In genere, tutto ciò che si trova all'interno della regione parallela viene eseguito da tutti i thread.

È inoltre possibile parallelizzare il ciclo nella regione parallela già esistente come segue:

#pragma omp parallel
{
  #pragma omp for
  for (int i = 0; i < n; i++)
    c[i] = a[i] + b[i];
}