关于MPI并行循环的问题

发布于 2024-10-31 14:00:27 字数 1631 浏览 4 评论 0原文

嘿, 我有一个关于 fortran 中 openmpi 的简短问题:我有这样的代码:

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 进行并行计算。 I) 和 III) 中的线性代码应该只计算一次,而 while 循环应该在多个处理器上运行......如何最好地实现它? 我的问题是 while 循环如何工作:例如,当处理器 1 计算 result1.bin 时,如何直接告诉处理器 2 计算 result2.bin?如果有 30 个文件并且我使用

mpirun -n 10 my_program ,

它将如何工作? 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

但它总是给我这样的错误: “从与 Open MP DO 或 PARALLEL DO 指令关联的 DO 循环中分支出来是非法的。”

总是关于此类代码的代码行:

read (F_RESULT,*,ERR=1) variable

其中 F_RESULT 是文件句柄...它可能有什么问题? 变量是在循环块之外定义的,我已经尝试将 OpenMP 指令设置为,

private(variable) 

以便每个线程都有自己的副本,但这没有成功! 到目前为止感谢您的帮助!

hey there,
I have a short question about openmpi in fortran: i have a code like this:

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...

Now I want to make this a parallel computation with openmpi. The linear code from I) and III) should only be computed once and the while-loops should be run on several processors... How to best realize it?
my problem is how the while-loop works: E.g. when processor 1 computes result1.bin, how to directly tell processor 2 to compute result2.bin? and how would it work if there are 30 files and I use

mpirun -n 10 my_program

? how does MPI "know" that after finishing computing one file, there are more files "waiting" to be processed: as soon as one processor has ended processing one file, THIS procesor should directly start over processing the next file in the queue..

thanks so far!

#

EDIT:

#

Hey there, it's me again... I wanted to give OpenMP a try too, so I used a chunk of your code which reads the existing files and afterwards loops them (and processes them):

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

now I tried the following code:

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

But it gives me always errors like that:
"It is illegal to branch out of a DO loop associated with an Open MP DO or PARALLEL DO directive."

Always about the codelines with this sort of code:

read (F_RESULT,*,ERR=1) variable

Where F_RESULT is a filehandle...What could be wrong about it?
variable is defined outside of the loop block, and I already tried to set OpenMP directive to

private(variable) 

so that each thread has his own copy, but that didn't work out!
Thanks so far for your help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

东走西顾 2024-11-07 14:00:27

也许最明智的方法是让其中一个进程预先计算文件总数,广播该数据,然后让每个人执行“他们的”文件:

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 问题:

因此,第一个循环是在文件并行处理开始之前计算文件数量的地方。文件的计数需要在文件并行处理之前完成,否则就不可能在处理器之间分配工作;在划分工作之前,您需要知道有多少个“工作单元”。 (这绝对不是唯一的方法,但它是最简单的)。

类似地,OMP DO 循环需要相当结构化的循环 - 需要一个像 do i=1,n 这样的简单循环,然后可以在线程之间轻松分解。 n 不需要编译进去,增量甚至不需要是 1,但它必须是在循环实际执行之前可以确定的事情。因此,例如,由于某些外部原因(例如文件不存在),您无法退出循环。

因此,您想要使用 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

但其他一切都将是相同的。再说一次,如果您想“内联”处理文件(例如,不在 sburoutine 中),您可以将文件处理代码放在“call processfile()”行所在的位置。

Probably the most sensible way to do this is to have one of the processes count the total number of files beforehand, broadcast that, and then have everyone do "their" files:

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

And then a simple test:

$ 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  

Updated to add the supplementary OpenMP question:

So that first loop is where the number of files is calculated, before the parallel processing of the files starts. That counting of the files needs to be done before the parallel processing of files can happen, because otherwise it's not possible to divide up the work between the processors; you need to know how many "work units" there are going to be before partitioning the work. (This isn't absolutely the only way to do things, but it's the most straightforward).

Similarly, OMP DO loops require quite structured loops -- there needs to be a simple loop like do i=1,n that can then be easily broken up between threads. n doesn't need to be compiled in, and the increment doesn't even need to be one, but it must be the sort of thing that can be known for sure before the loop is actually executed. So, for instance, you can't exit out of the loop because of some external cause (like the non-presence of a file.)

So what you'd want to do with OpenMP is to do the same file counting, and leave that alone, but then in the processing loop, use a parallel do construct. So, after stripping out the MPI stuff, you'd have something that looks like:

    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

but everything else would be the same. And again, if you want to process the files "inline" (eg, not in a sburoutine), you'd put the file-processing code in where the 'call processfile()' line is.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文