我目前正在开发用于科学应用的并行代码。我必须从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
这有什么问题?
答案 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_ISEND
和MPI_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()
死锁,这将有所帮助。