2011-04-10 131 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