Fortran

时间:2017-11-12 11:01:24

标签: fortran mpi

我目前正在开发用于科学应用的并行代码。我必须从p0到p1以及从p1到p0交换一些缓冲区(我在处理器边界之间创建鬼点)。

此示例代码可以汇总错误:

program test
use mpi
implicit none

integer id, ids, idr, ierr, tag, istat(MPI_STATUS_SIZE)
real sbuf, rbuf

call mpi_init(ierr)

call MPI_COMM_RANK(MPI_COMM_WORLD,id,ierr)

if(id.eq.0) then
ids=0
idr=1
sbuf=1.5
tag=id
else    
ids=1
idr=0
sbuf=3.5
tag=id
endif

call mpi_send(sbuf,1,MPI_REAL,ids,tag,MPI_COMM_WORLD,ierr)

call mpi_recv(rbuf,1,MPI_REAL,idr,tag,MPI_COMM_WORLD,istat,ierr)

call mpi_finalize(ierr)
return
end

这有什么问题?

2 个答案:

答案 0 :(得分:2)

首先使用MPI进行编码可能很困难,并且您正在完成制作示例代码的步骤。您发布的示例代码因死锁而挂起。这两个进程都忙MPI_SEND - 并且发送无法完成,直到它被MPI_RECV编辑。所以代码卡住了。

这个问题有两种常见的方法。

以特定顺序发送和接收

这是一种简单易懂的解决方案。编码您的发送和接收操作,以免任何人遇到困难。对于2过程测试用例,您可以这样做:

if (id==0) then

   call mpi_send(sbuf,1,MPI_REAL,ids,tag,MPI_COMM_WORLD,ierr)
   call mpi_recv(rbuf,1,MPI_REAL,idr,tag,MPI_COMM_WORLD,istat,ierr)
else
   call mpi_recv(rbuf,1,MPI_REAL,idr,tag,MPI_COMM_WORLD,istat,ierr)
   call mpi_send(sbuf,1,MPI_REAL,ids,tag,MPI_COMM_WORLD,ierr)
endif

现在,进程1首先接收 ,因此永远不会出现死锁。这个特定的例子不可扩展,但有各种循环结构可以提供帮助。您可以想象一个例程,将数据从每个进程发送到其他每个进程:

do sending_process=1,nproc
   if (id == sending_process) then
      ! -- I am sending
      do destination_process = 1,nproc
         if (sending_process == destination_process) cycle
         call MPI_SEND ! Send to destination_process
      enddo
    elseif
       ! -- I am receiving
       call MPI_RECV ! Receive from sending_process
    endif
 enddo

这种方法效果很好,很容易理解。我建议这个结构适合初学者。

但是,对于真正的大问题,它有几个问题。您发送的消息数等于平方的进程数,这会使大型网络过载。此外,根据您的操作,您可能不需要将每个进程的数据发送到每个其他进程。 (我怀疑在你提到幽灵的情况下这是真的。)你可以修改上面的循环只发送需要的数据,但是对于那些情况有更好的选择。

使用非阻止MPI操作

对于许多核心问题,这通常是最好的解决方案。我建议坚持使用简单的MPI_ISENDMPI_IRECV。在这里,您开始所有必要的发送和接收,然后等待。 在这里,我使用了一些已经设置的列表结构,它定义了每个进程的必要目的地的完整列表。

! -- Open sends
do d=1,Number_Destinations
   idest = Destination_List(d)

   call MPI_ISEND ! To destination d
enddo

! -- Open receives
do s=1,Number_Senders
   isend = Senders_List(s)
   call MPI_IRECV ! From source s
enddo

call MPI_WAITALL

此选项可能看起来更简单但。您必须事先设置所有必需的列表,缓冲区大小和数据对齐存在各种潜在问题。即使如此,它通常也是 big 代码的最佳答案。

答案 1 :(得分:0)

正如弗拉基米尔所指出的,你的代码太不完整,无法提供明确的答案。

话虽如此,这可能是一个众所周知的错误。

MPI_Send()可能会阻止。从实用的角度来看,MPI_Send()可能会在发送消息时立即返回,但在发送消息时可能会阻止。注意 small large 取决于您的MPI库,您正在使用的互连以及其他运行时参数。 MPI_Send()可能会阻止,直到MPI_Recv()张贴在另一端。

在同一代码块中,您似乎是MPI_Send()MPI_Recv(),因此您可以尝试使用MPI_Sendrecv()一次性执行此操作。 MPI_Sendrecv()会在引擎盖下发出非阻止发送,如果您的问题确实是MPI_Send()死锁,这将有所帮助。