2012-08-23 151 views
9

我在這裏是一個新手,並且是C語言的初級程序員。我在使用openmp加速for循環時遇到了一些問題。下面是一個簡單的例子:OpenMP和C並行循環:爲什麼我的代碼在使用OpenMP時變慢?

#include <stdlib.h> 
#include <stdio.h> 
#include <gsl/gsl_rng.h> 
#include <omp.h> 

gsl_rng *rng; 

main() 
{ 
int i, M=100000000; 
double tmp; 

/* initialize RNG */ 
gsl_rng_env_setup(); 
rng = gsl_rng_alloc (gsl_rng_taus); 
gsl_rng_set (rng,(unsigned long int)791526599); 

// option 1: parallel   
    #pragma omp parallel for default(shared) private(i, tmp) schedule(dynamic) 
    for(i=0;i<=M-1;i++){ 
    tmp=gsl_ran_gamma_mt(rng, 4, 1./3); 
    } 


// option 2: sequential  
    for(i=0;i<=M-1;i++){ 
    tmp=gsl_ran_gamma_mt(rng, 4, 1./3); 
    } 
} 

該代碼從M次迭代的伽馬隨機分佈繪製。事實證明,使用openmp(選項1)的並行方法大約需要1分鐘,而順序方法(選項2)僅需要20秒。當使用openmp運行時,我可以看到cpu使用率爲800%(我使用的服務器有8個CPU)。系統是使用GCC 4.1.3的Linux。我使用的編譯命令是gcc -fopenmp -lgsl -lgslcblas -lm(我正在使用GSL)

我做錯了什麼?請幫幫我!謝謝!

P.S.正如一些用戶指出的那樣,這可能是由rng引起的。但是,即使我更換

tmp=gsl_ran_gamma_mt(rng, 4, 1./3); 

通過說

tmp=1000*10000; 

問題仍然存在......

+0

你不應該讓你的循環變量是私人的 - OpenMP會照顧到這一點。我不知道這是否會影響執行,但你應該修復它並重新測試。 –

+0

另外,請注意,tmp = 1000 * 10000可能會被編譯器優化到noop,這樣會扭曲您的時序。 –

+0

你確定實際上有8個CPU嗎?它可能是一個超線程的四核? –

回答

12

gsl_ran_gamma_mt可能鎖定在rng以防止併發問題(如果沒有,您的並行代碼可能包含競爭條件,從而產生錯誤的結果)。那麼解決方案將是爲每個線程分別設置一個rng實例,從而避免鎖定。

+1

非常感謝!但問題仍然存在,如果我用tmp = 1000 * 10000代替tmp = gsl_ran_gamma_mt(rng,4,1./3) – user1620200

+0

@ user1620200奇怪的話,應該會大幅度減少。當然,並行計算的開銷仍然很大,因爲實際的計算速度很快,即使有很多迭代。動態計劃沒有幫助(嘗試一個靜態計劃,因爲任務都具有相同的大小,所以這裏沒有任何動態計劃的理由)。最後,請嘗試Stephane的建議,但如果這是問題,我會很驚訝,因爲這應該進行優化。 –

+0

謝謝。我發現如果我擺脫了時間表(動態),問題就消失了!我想知道爲什麼? – user1620200

5

你的rng變量是共享的,所以線程花費他們所有的時間等待能夠使用隨機數生成器。給每個線程一個單獨的RNG實例。這可能意味着使RNG初始化代碼也並行運行。

+0

非常感謝!但問題仍然存在,如果我用tmp = 1000 * 10000替換tmp = gsl_ran_gamma_mt(rng,4,1./3); – user1620200

1

再次感謝大家的幫助。我剛剛發現,如果我擺脫了

schedule(dynamic) 

在代碼中,問題消失。但爲什麼呢?

+1

「動態」調度相當昂貴,只能用於迭代需要大量時間才能完成的情況,但這次每次迭代都會有很大差異。 「引導」更加昂貴,因爲它使得迭代塊越來越小。使用'static'調度進行具有固定計算時間量的迭代。 –

+0

非常感謝Hristo Iliev! – user1620200

+1

我認爲你可以接受你自己的答案,因爲你是解決問題的人。 –