2016-06-06 14 views
11

Mam dwie wersje kodu, które dają równoważne wyniki, gdy próbuję zrównoleglić tylko wewnętrzną pętlę zagnieżdżonej pętli for. Nie uzyskuję zbyt dużej prędkości, ale nie spodziewałem się 1-do-1, ponieważ próbuję tylko zrównoleglić wewnętrzną pętlę.jak uniknąć narzutów OpenMP w zagnieżdżonych pętlach

Moje główne pytanie brzmi: dlaczego te dwie wersje mają podobne środowiska wykonawcze? Czy druga wersja nie wyświetla wątków tylko raz i nie pozwala na narzut uruchamiania nowych wątków w każdej iteracji ponad i, tak jak w pierwszej wersji?

Pierwsza wersja kodu uruchamia się nici w każdej iteracji pętli zewnętrznej, jak to:

for(i=0; i<2000000; i++){ 
    sum = 0; 
    #pragma omp parallel for private(j) reduction(+:sum) 
    for(j=0; j<1000; j++){ 
    sum += 1; 
    } 
    final += sum; 
} 
printf("final=%d\n",final/2000000); 

Z tego wyjścia i wykonywania:

OMP_NUM_THREADS = 1

final=1000 
real 0m5.847s 
user 0m5.628s 
sys  0m0.212s 

OMP_NUM_THREADS = 4

final=1000 
real 0m4.017s 
user 0m15.612s 
sys  0m0.336s 

Druga wersja kodu rozpoczyna wątki raz przed zewnętrznej pętli i parallelizes wewnętrznej pętli tak (?):

#pragma omp parallel private(i,j) 
for(i=0; i<2000000; i++){ 
    sum = 0; 
    #pragma omp barrier 
    #pragma omp for reduction(+:sum) 
    for(j=0; j<1000; j++){ 
    sum += 1; 
    } 
    #pragma omp single 
    final += sum; 
} 
printf("final=%d\n",final/2000000); 

Z tego wyjścia i wykonywania:

OMP_NUM_THREADS = 1

final=1000 
real 0m5.476s 
user 0m4.964s 
sys  0m0.504s 

OMP_NUM_THREADS = 4

final=1000 
real 0m4.347s 
user 0m15.984s 
sys  0m1.204s 

dlaczego czy druga wersja jest znacznie szybsza od pierwszej? Czy to nie pozwala na uruchamianie wątków w każdej iteracji pętli lub czy robię coś nie tak?

+3

Prawdopodobnie dlatego, że Twoja implementacja OpenMP skutecznie przetłumaczyła twoją pierwszą wersję na twoją drugą wersję. Większość implementacji jest wystarczająco inteligentna, aby utrzymać twoje wątki przy życiu, jeśli widzi, że są ciągle tworzone wewnątrz zewnętrznej pętli. – NoseKnowsAll

+0

Twoja druga wersja jest lepsza nawet w przypadku pul wątków, zobacz [tutaj] (https://stackoverflow.com/questions/71/openmp-nested-for-loop-becomes-faster-when-having-parallel-before-outer- loop/31382775 # 31382775). –

+0

Och, jestem zaskoczony, że twoja druga wersja jest wolniejsza. Czy skompilowałeś z optymalizacją? Próbowałem twój kod z optymalizacją i bez OpenMP wewnętrzna pętla jest optymalizowana do 1000, ale z OpenMP nie jest. Prawdopodobnie nie skompilowałeś się z optymalizacją. –

Odpowiedz

1

Implementacja OpenMP może wykorzystywać łączenie wątków, aby wyeliminować narzut początkowych wątków podczas napotkania równoległego konstruktu. Pula wątków OMP_NUM_THREADS jest uruchamiana dla pierwszej równoległej konstrukcji, a po zakończeniu konstruowania wątki podrzędne są zwracane do puli. Te bezczynne wątki mogą być ponownie przydzielane, gdy napotkana zostanie późniejsza konstrukcja równoległa.

Zobacz na przykład to wyjaśnienie thread pooling in the Sun Studio OpenMP implementation.

+0

@nick, z zainteresowaniem, z jakiej wersji kompilatora C/OpenMP korzystasz? –

0

Wygląda na to, że odtwarza się kolejne kroki: Amdahl's Law: Mówi o procesie równoległym w stosunku do własnego obciążenia. Jedną z rzeczy, które znalazł Amadhl, było to, niezależnie od tego, jak dużo równoległości wprowadziłeś do programu, zawsze będzie musiało zacząć się od tego samego przyspieszenia. Paralelizm zaczyna jedynie poprawiać czas pracy/wydajność, gdy program wymaga wystarczającej ilości pracy, aby zrekompensować dodatkową moc przetwarzania.

Powiązane problemy