Różnica między #pragma omp parallel i #pragma omp parallel dla

Dec 11 2020

Jestem nowy OpenMPi próbuję uruchomić program, który dodaje dwie tablice przy użyciu OpenMP. W samouczku dotyczącym OpenMP dowiedziałem się, że musimy używać #pragma omp równolegle for podczas korzystania z OpenMP w pętli for . Ale próbowałem też tego samego z równoległym #pragma omp i to również daje mi prawidłowe wyjście. Poniżej znajdują się fragmenty kodu tego, co próbuję przekazać.

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

i

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

Jaka jest różnica między tymi dwoma?

Odpowiedzi

5 dreamcrash Dec 11 2020 at 15:14

Plik

#pragma omp parallel:

utworzy parallel regionz zespołem threads, w którym każdy wątek wykona cały blok kodu, który parallel regionobejmuje.

Z OpenMP 5.1 można przeczytać bardziej formalny opis:

Gdy wątek napotyka konstrukcję równoległą , tworzony jest zespół wątków w celu wykonania regionu równoległego (..). Wątek, który napotkał konstrukcję równoległą, staje się głównym wątkiem nowego zespołu, a numer wątku wynosi zero na czas trwania nowego regionu równoległego. Wszystkie wątki w nowym zespole, w tym wątek podstawowy, wykonują region. Po utworzeniu zespołu liczba wątków w zespole pozostaje stała przez cały czas trwania tego równoległego regionu.

The:

#pragma omp parallel for

utworzy parallel region(jak opisano wcześniej), a do threadstego regionu zostaną przypisane iteracje pętli, którą obejmuje, przy użyciu default chunk size, i default schedulektóry jest zwykle static . Należy jednak pamiętać, że default schedulemogą się one różnić między różnymi konkretnymi wdrożeniami OpenMPstandardu.

Z OpenMP 5.1 możesz przeczytać bardziej formalny opis:

Konstrukcja pętli współdzielenia pracy określa, że ​​iteracje jednej lub większej liczby skojarzonych pętli będą wykonywane równolegle przez wątki w zespole w kontekście ich niejawnych zadań. Iteracje są dystrybuowane między wątkami, które już istnieją w zespole wykonującym region równoległy, z którym wiąże się region pętli współdzielenia pracy .

Co więcej ,

Konstrukcja pętli równoległej jest skrótem do określania konstrukcji równoległej zawierającej konstrukcję pętli z jedną lub większą liczbą skojarzonych pętli i bez innych instrukcji.

Lub nieformalnie #pragma omp parallel forjest to połączenie konstruktora #pragma omp parallelz #pragma omp for. W twoim przypadku oznaczałoby to, że:

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

jest semantycznie i logicznie taka sama jak:

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

TL; DR: W twoim przykładzie #pragma omp parallel forpętla zostanie zrównoleglona między wątkami ( tj. Iteracje pętli zostaną podzielone między wątki), podczas gdy we #pragma omp parallel wszystkich wątkach wykonają (równolegle) wszystkie iteracje pętli.

Aby uczynić go bardziej ilustracyjnym, z 4wątkami #pragma omp parallel, wynikałoby coś takiego:

podczas gdy #pragma omp parallel forz a chunk_size=1i static schedule dałoby coś takiego:

Pod względem kodu pętla zostałaby przekształcona w coś logicznie podobnego do:

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

gdzie omp_get_thread_num ()

Procedura omp_get_thread_num zwraca numer wątku, w ramach bieżącego zespołu, wątku wywołującego.

i omp_get_num_threads ()

Zwraca liczbę wątków w bieżącym zespole. W sekwencyjnej sekcji programu omp_get_num_threads zwraca 1.

czyli innymi słowy for(int i = THREAD_ID; i < n; i += TOTAL_THREADS). Z THREAD_IDprzedziałem od 0do TOTAL_THREADS - 1i TOTAL_THREADSreprezentującym całkowitą liczbę wątków zespołu utworzonych w regionie równoległym.

Dowiedziałem się, że musimy używać równoległego #pragma omp for podczas korzystania z OpenMP w pętli for. Ale próbowałem też tego samego z równoległym #pragma omp i to również daje mi prawidłowe wyjście.

Daje ci to samo wyjście, ponieważ w twoim kodzie:

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

tablica ai tablica bsą tylko odczytywane, a tablica c[i]jest jedyną aktualizowaną, a jej wartość nie zależy od tego, ile razy iteracja izostanie wykonana. Niemniej jednak, z #pragma omp parallel forkażdym wątkiem będzie aktualizował swój własny i, podczas gdy z #pragma omp parallelwątkami będzie aktualizował te same is, a tym samym nadpisując wartości innych.

Teraz spróbuj zrobić to samo z następującym kodem:

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

i

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

natychmiast zauważysz różnicę.

2 DanielLangr Dec 11 2020 at 15:16

W drugim przypadku pętla nie jest zrównoleglona. Mianowicie cała pętla jest wykonywana w każdym wątku . Ogólnie rzecz biorąc, wszystko, co znajduje się wewnątrz regionu równoległego, jest wykonywane przez wszystkie wątki.

Możesz dodatkowo zrównoleglać pętlę w już istniejącym regionie równoległym w następujący sposób:

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