Różnica między #pragma omp parallel i #pragma omp parallel dla
Jestem nowy OpenMP
i 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
Plik
#pragma omp parallel
:
utworzy parallel region
z zespołem threads
, w którym każdy wątek wykona cały blok kodu, który parallel region
obejmuje.
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 threads
tego regionu zostaną przypisane iteracje pętli, którą obejmuje, przy użyciu default chunk size
, i default schedule
który jest zwykle static
. Należy jednak pamiętać, że default schedule
mogą się one różnić między różnymi konkretnymi wdrożeniami OpenMP
standardu.
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 for
jest to połączenie konstruktora #pragma omp parallel
z #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 for
pę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 4
wątkami #pragma omp parallel
, wynikałoby coś takiego:

podczas gdy #pragma omp parallel for
z a chunk_size=1
i 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_ID
przedziałem od 0
do TOTAL_THREADS - 1
i TOTAL_THREADS
reprezentują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 a
i tablica b
są tylko odczytywane, a tablica c[i]
jest jedyną aktualizowaną, a jej wartość nie zależy od tego, ile razy iteracja i
zostanie wykonana. Niemniej jednak, z #pragma omp parallel for
każdym wątkiem będzie aktualizował swój własny i
, podczas gdy z #pragma omp parallel
wątkami będzie aktualizował te same i
s, 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ę.
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];
}