2011-04-10 118 views
2
並行循環

嘿, 我對自己在FORTRAN了openmpi短的問題:我有一個這樣的代碼:問題有關MPI

I) definitions of vars & linear code, setting up some vars for later usage 
II) a while loop which works like that in pseudocode: 

nr=1 
while(true) 
{ 
    filename='result'//nr//'.bin' (nr converted to string) 
    if(!file_exists(filename)) 
    goto 100 

    // file exists... so do something with it 
    // calculations, read/write... 
    nr=nr+1 
} 
100 continue 
III) some more linear code... 

現在,我想使這個用了openmpi並行計算。從我的線性代碼)和III)應該只計算一次和while循環應該在多個處理器上運行...如何最好地實現它? 我的問題是,while循環是如何工作的:例如當處理器1計算result1.bin時,如何直接告訴處理器2計算result2.bin?以及如何,如果有30個文件將它的工作,我用

的mpirun -n 10 MY-

?如何MPI「知道」整理計算一個文件後,有更多的文件「等待」被處理:只要一個處理器已經結束處理一個文件,這個應該。處理器直接重新開始處理隊列中的下一個文件..

感謝到目前爲止!

編輯:

嘿,這又是我......我想給OpenMP的一個嘗試過,所以我用你的代碼塊讀取現有的文件和事後循環他們(和處理它們):

nfiles = 0 
do 
    write(filename,FMT='(A,I0,A)'), prefix, nfiles+1, suffix 
    inquire(file=trim(filename),exist=exists) 
    if (not(exists)) exit 
    nfiles = nfiles + 1 
enddo 

現在我嘗試下面的代碼:

call omp_set_num_threads(2) 
!$OMP PARALLEL 
!$OMP DO 
do i=startnum, endnum 
    write(filename,FMT='(A,I0,A)'), prefix, i, suffix 
    ...CODE DIRECTLY HERE TO PROCESS THE FILE... 
enddo 
!$OMP END DO 
!$OMP END PARALLEL 

但它給我總是這樣的錯誤: 「這是違法的分支機構,以開放的MP相關聯的DO或PARALLEL DO循環的DO指令」

總是對與這種代碼的代碼行:

read (F_RESULT,*,ERR=1) variable 

凡F_RESULT是一個文件句柄......出了什麼問題呢? 變量環形塊外定義,我已經嘗試過OpenMP指令設置爲

private(variable) 

,這樣每個線程都有自己的副本,但沒有工作了! 謝謝到目前爲止您的幫助!

+0

編輯用mpi替換openmpi;這不是openmpi特有的。 – 2011-04-10 17:26:21

回答

5

可能是最明智的方式做到這一點是有過程的一個統計文件總數事前,播出,然後讓每個人都做「自己」的文件:

program processfiles 
    use mpi 
    implicit none 

    integer :: rank, comsize, ierr 
    integer :: nfiles 
    character(len=6) :: prefix="result" 
    character(len=4) :: suffix=".bin" 
    character(len=50) :: filename 
    integer :: i 
    integer :: locnumfiles, startnum, endnum 
    logical :: exists 

    call MPI_Init(ierr) 
    call MPI_Comm_size(MPI_COMM_WORLD, comsize, ierr) 
    call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr) 

    ! rank zero finds number of files 
    if (rank == 0) then 
     nfiles = 0 
     do 
      write(filename,FMT='(A,I0,A)'), prefix, nfiles+1, suffix 
      inquire(file=trim(filename),exist=exists) 
      if (not(exists)) exit 
      nfiles = nfiles + 1 
     enddo 
    endif 
    ! make sure everyone knows 
    call MPI_Bcast(nfiles, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) 

    if (nfiles /= 0) then 
     ! calculate who gets what file 
     locnumfiles = nfiles/comsize 
     if (locnumfiles * comsize /= nfiles) locnumfiles = locnumfiles + 1 
     startnum = locnumfiles * rank + 1 
     endnum = startnum + locnumfiles - 1 
     if (rank == comsize-1) endnum = nfiles 
     do i=startnum, endnum 
      write(filename,FMT='(A,I0,A)'), prefix, i, suffix 
      call processfile(rank,filename) 
     enddo 
    else 
     if (rank == 0) then 
      print *,'No files found; exiting.' 
     endif 
    endif 
    call MPI_Finalize(ierr) 

    contains 
     subroutine processfile(rank,filename) 
      implicit none 
      integer, intent(in) :: rank 
      character(len=*), intent(in) :: filename 
      integer :: unitno 
      open(newunit=unitno, file=trim(filename)) 
      print '(I4,A,A)',rank,': Processing file ', filename 
      close(unitno) 
     end subroutine processfile 
end program processfiles 

然後一個簡單的測試:

$ seq 1 33 | xargs -I num touch "result"num".bin" 
$ mpirun -np 2 ./processfiles 

    0: Processing file result1.bin          
    0: Processing file result2.bin          
    0: Processing file result3.bin          
    0: Processing file result4.bin          
    0: Processing file result5.bin          
    0: Processing file result6.bin          
    1: Processing file result18.bin          
    0: Processing file result7.bin          
    0: Processing file result8.bin          
    1: Processing file result19.bin          
    0: Processing file result9.bin          
    1: Processing file result20.bin          
    0: Processing file result10.bin          
    1: Processing file result21.bin          
    1: Processing file result22.bin          
    0: Processing file result11.bin          
    1: Processing file result23.bin          
    0: Processing file result12.bin          
    1: Processing file result24.bin          
    1: Processing file result25.bin          
    0: Processing file result13.bin          
    0: Processing file result14.bin          
    1: Processing file result26.bin          
    1: Processing file result27.bin          
    0: Processing file result15.bin          
    0: Processing file result16.bin          
    1: Processing file result28.bin          
    1: Processing file result29.bin          
    1: Processing file result30.bin          
    0: Processing file result17.bin          
    1: Processing file result31.bin          
    1: Processing file result32.bin          
    1: Processing file result33.bin 

更新添加補充OpenMP的問題:

爲:F IRST循環是,在其中計算的文件數,文件開始的並行處理之前。該文件的那計數需要做之前的文件的並行處理可能發生的,因爲否則它不可能瓜分處理器之間的工作;您需要知道在分配工作之前將會有多少「工作單位」。(這不是絕對唯一的辦法,但它是最直接的)。

同樣,OMP DO循環需要相當結構化的循環 - 需要有一個簡單的循環,如do i=1,n,然後可以很容易地在線程之間分解。 n不需要編譯,增量甚至不需要是一個,但它必須是在實際執行循環之前可以確定的那種事情。因此,例如,由於某些外部原因(如不存在文件),您無法退出循環。

因此,您想要對OpenMP執行的操作是執行相同的文件計數,然後單獨離開,但在處理循環中,使用並行do結構。所以,在剝離MPI的東西之後,你會看到如下所示的東西:

do 
     write(filename,FMT='(A,I0,A)'), prefix, nfiles+1, suffix 
     inquire(file=trim(filename),exist=exists) 
     if (.not.exists) exit 
     nfiles = nfiles + 1 
    enddo 

    if (nfiles /= 0) then 
     !$OMP PARALLEL SHARED(nfiles,prefix,suffix) PRIVATE(i,thread,filename) 
     thread = omp_get_thread_num() 
     !$OMP DO 
     do i=1, nfiles 
      write(filename,FMT='(A,I0,A)'), prefix, i, suffix 
      call processfile(thread,filename) 
     enddo 
     !$OMP END DO 
     !$OMP END PARALLEL 
    else 
     print *,'No files found; exiting.' 
    endif 

但是其他的東西都是一樣的。再次,如果你想處理文件「inline」(例如,不在sburoutine中),你可以將文件處理代碼放在'call processfile()'行的位置。

+0

哦,很酷,看起來很酷...唯一的問題是,由於所有已定義的變量等等,我很難將現有代碼分離到「子程序」中,這些變量存在於while循環中(定義/聲明在while循環之前)...有沒有更簡單的方法?但是,不過謝謝,我一定會嘗試一下,看看將現有的代碼分成幾部分! – tim 2011-04-10 18:03:04

+0

嗯,當然,你可以把處理放在調用子程序的地方。然而,從長遠來看,如果你將功能分解成功能和子程序,你會發現你的軟件維護起來更容易 - 更容易看到發生了什麼。 – 2011-04-10 18:28:38

+0

嘿那裏,編輯我原來的帖子,因爲我不能在這裏發表評論足夠的代碼... – tim 2011-04-10 21:45:29