在fortran下進行openmp並行計算編程


最近寫水動力的程序,體系太大,必須用並行才能算的動,無奈只好找了並行編程的資料學習了。我想我沒有必要在博客里開一個什么並行編程的教程之類,因為網上到處都是,我就隨手記點重要的筆記吧。這里主要是openmp的~

1 臨界與歸約
   在涉及到openmp的並行時,最需要注意的就是被並行的區域中的公共變量,對於需要reduce的變量,尤其要注意,比如這段代碼:

program main
implicit none
include 'omp_lib.h'
integer N,M,i
real(kind=8) t
N=20000
t=0.0
!$OMP PARALLEL DO
do i=1,N
t=t+float(i);
M=OMP_get_num_threads()
enddo
write(*, "('t =  ', F20.5, ' running on ', I3, ' threads.')") t,M
pause
stop
end

 串行代碼可以很容易的得到正確結果:

t = 200010000.00000 running on   1 threads.
不幸的是,如果是並行的話,可能每次都得到一個不同的結果:
t = 54821260.00000 running on   8 threads.
t = 54430262.00000 running on   8 threads.
....
原因很簡單,假設do被並行了兩個線程,A1,A2,則每個線程都可以t,在其中一個線程訪問t的時候,另一個線程修改了t,導致t的某些值“丟了”。解決方法有兩種,第一種就是“臨界”,就是鎖定t:

!$OMP PARALLEL DO
do i = 1, N
!$OMP CRITICAL
t = t+float(i)
            !$OMP END CRITICAL
           M = OMP_get_num_threads()
enddo

這樣每個時刻只有一個線程能訪問這個變量。顯然,這種方法會遇到“短木板瓶頸”,更高效的方法是使用“歸約”:

!$OMP PARALLEL DO REDUCTION(+:t)
do i = 1, N
t = t+float(i)
           M = OMP_get_num_threads()
enddo

 此時程序會自動在內部實現儲存部分和之類的操作。這個方法比臨界要高效的多,這是我這里運行的結果:臨界0.005s, 歸約0.003s。對於大任務,速度會更快。

2 條件並行
有時,對於小的循環,多線程的消耗超過了並行的節省時間,顯然這是就不值得並行了。比如

do i = 1, N
t = t+(sin(float(i))+2.0)**0.3+abs(cos(log(float(i))))**0.7
M = OMP_get_num_threads()
enddo

發現:

N              20000         5000
tserial       0.027s        0.003
tparallel    0.013s       0.004

推斷在N>5000時應該並行更有效,可以加上條件編譯:

!$OMP PARALLEL DO REDUCTION(+:t) if(N > 5000)

3 負載平衡
不同線程間的工作量“不平等”是個很麻煩的問題,他會大大降低程序並行效率,比如這個程序:

N = 5000
!$OMP PARALLEL DO PRIVATE(j)
do i = 1, N
do j = i, N
a(j, i) = fun(i, j)
enddo
enddo

其中fun是個費時的函數,串行與8核CPU並行的時間比較:
serial:3m28.007s;paralle:49.940s  加速比 4.1 太低了

      這個顯然與CPU個數無關。分析上面的循環發現,i=1時內層需要N個循環,而i=2500時候內部僅僅N/2個循環,極其不平衡,因此可以顯式指定其調動模式,改進負載平衡。NAMD中有個LDB模塊就是干這個的。SCHEDULE一般格式:
SCHEDULE(type, chunk)

可以比較一下:

!$OMP PARALLEL DO SCHEDULE(static,1)         34.955s
!$OMP PARALLEL DO SCHEDULE(dynamic,1)   29.773s
     !$OMP PARALLEL DO SCHEDULE(guided,1)      53.116s
     !$OMP PARALLEL DO SCHEDULE(static,500)      48.822s
     !$OMP PARALLEL DO SCHEDULE(dynamic,500)  50.485s
!$OMP PARALLEL DO SCHEDULE(guided,500)     51.611s

      需要注意的是,實際中很難一下看出那種調度方式最好。通常需要實際試驗,這還與你調用的CPU數目有關。SCHEDULE中,增大chunk可以提高緩存命中率,但是以降低負載平衡為代價的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM