在 4 个线程中使用 MPI_SENDRECV 的问题
Problem with using MPI_SENDRECV with 4 threads
作为一个最小的问题,我试图在 4 个处理器之间发送一个整数:0 -> 3(等级 0
发送到等级 3
并从等级 3
接收),2 -> 1 , 1 -> 2, 3 -> 0。它永远不会执行完并挂起,可能是在等待其他线程的响应。
我正在使用 mpif90 ...
和 运行 mpiexec -np 4 ...
编译代码。以下是最小片段:
program sendrecv
implicit none
include "mpif.h"
integer :: foo, bar
integer :: mpi_rank, mpi_size, ierr
integer :: mpi_sendto, mpi_recvfrom
integer :: istat(MPI_STATUS_SIZE), status, i
call MPI_INIT(ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, mpi_size, ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, mpi_rank, ierr)
print *, "SENDING..."
if (mpi_rank .eq. 0) then
mpi_sendto = 3; mpi_recvfrom = 3
else if (mpi_rank .eq. 1) then
mpi_sendto = 2; mpi_recvfrom = 2
else if (mpi_rank .eq. 2) then
mpi_sendto = 1; mpi_recvfrom = 1
else
mpi_sendto = 0; mpi_recvfrom = 0
end if
foo = mpi_rank
do i = 1, 5
foo = mpi_rank
call MPI_SENDRECV(foo, 1,&
& MPI_INTEGER, mpi_sendto, mpi_rank * 10 + i,&
& bar, 1,&
& MPI_INTEGER, mpi_recvfrom, mpi_rank * 10 + i,&
& MPI_COMM_WORLD, istat, ierr)
end do
print *, "...DONE"
call MPI_FINALIZE(ierr)
end
我真的不明白为什么这个程序会挂起,也许我遗漏了什么或者做错了什么。如果我理解正确,MPI_SENDRECV
只是非阻塞 send
和 recv
有两个 wait
-s。在那种情况下,比如说,如果 rank=0
发送到 rank=3
它接收它应该没有任何问题,对吗?
我尝试从不同的线程 sending/receiving,即这样做:
if (mpi_rank .eq. 0) then
mpi_sendto = 1; mpi_recvfrom = 3
else if (mpi_rank .eq. 1) then
mpi_sendto = 2; mpi_recvfrom = 0
else if (mpi_rank .eq. 2) then
mpi_sendto = 3; mpi_recvfrom = 1
else
mpi_sendto = 0; mpi_recvfrom = 2
end if
仍然无法正常工作。
UPD 正如所指出的,执行 SENDRECV
时标签应该相同,但是如果在循环中执行此调用,类似的标签不会帮助不大(见修改后的代码)。旧版本:
call MPI_SENDRECV(foo, 1,&
& MPI_INTEGER, mpi_sendto, 200,&
& bar, 1,&
& MPI_INTEGER, mpi_recvfrom, 100,&
& MPI_COMM_WORLD, status, ierr)
UPD#2 实际上,如果有人感兴趣,我发现 discussion 正是关于 SENDRECV
-s 可能死锁的问题有时。
术语"thread"在这里有误导性,你应该谈论MPI任务或MPI进程(两者是等价的)。
根本原因是标签不匹配。您使用标签 200
发送,但接收时使用标签 100
.
此外,您应该使用 istat
而不是 status
作为 MPI_Sendrecv()
的状态参数。
这是修复程序的方法
call MPI_SENDRECV(foo, 1,&
& MPI_INTEGER, mpi_sendto, 200,&
& bar, 1,&
& MPI_INTEGER, mpi_recvfrom, 200,&
& MPI_COMM_WORLD, istat, ierr)
作为一个最小的问题,我试图在 4 个处理器之间发送一个整数:0 -> 3(等级 0
发送到等级 3
并从等级 3
接收),2 -> 1 , 1 -> 2, 3 -> 0。它永远不会执行完并挂起,可能是在等待其他线程的响应。
我正在使用 mpif90 ...
和 运行 mpiexec -np 4 ...
编译代码。以下是最小片段:
program sendrecv
implicit none
include "mpif.h"
integer :: foo, bar
integer :: mpi_rank, mpi_size, ierr
integer :: mpi_sendto, mpi_recvfrom
integer :: istat(MPI_STATUS_SIZE), status, i
call MPI_INIT(ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, mpi_size, ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, mpi_rank, ierr)
print *, "SENDING..."
if (mpi_rank .eq. 0) then
mpi_sendto = 3; mpi_recvfrom = 3
else if (mpi_rank .eq. 1) then
mpi_sendto = 2; mpi_recvfrom = 2
else if (mpi_rank .eq. 2) then
mpi_sendto = 1; mpi_recvfrom = 1
else
mpi_sendto = 0; mpi_recvfrom = 0
end if
foo = mpi_rank
do i = 1, 5
foo = mpi_rank
call MPI_SENDRECV(foo, 1,&
& MPI_INTEGER, mpi_sendto, mpi_rank * 10 + i,&
& bar, 1,&
& MPI_INTEGER, mpi_recvfrom, mpi_rank * 10 + i,&
& MPI_COMM_WORLD, istat, ierr)
end do
print *, "...DONE"
call MPI_FINALIZE(ierr)
end
我真的不明白为什么这个程序会挂起,也许我遗漏了什么或者做错了什么。如果我理解正确,MPI_SENDRECV
只是非阻塞 send
和 recv
有两个 wait
-s。在那种情况下,比如说,如果 rank=0
发送到 rank=3
它接收它应该没有任何问题,对吗?
我尝试从不同的线程 sending/receiving,即这样做:
if (mpi_rank .eq. 0) then
mpi_sendto = 1; mpi_recvfrom = 3
else if (mpi_rank .eq. 1) then
mpi_sendto = 2; mpi_recvfrom = 0
else if (mpi_rank .eq. 2) then
mpi_sendto = 3; mpi_recvfrom = 1
else
mpi_sendto = 0; mpi_recvfrom = 2
end if
仍然无法正常工作。
UPD 正如所指出的,执行 SENDRECV
时标签应该相同,但是如果在循环中执行此调用,类似的标签不会帮助不大(见修改后的代码)。旧版本:
call MPI_SENDRECV(foo, 1,&
& MPI_INTEGER, mpi_sendto, 200,&
& bar, 1,&
& MPI_INTEGER, mpi_recvfrom, 100,&
& MPI_COMM_WORLD, status, ierr)
UPD#2 实际上,如果有人感兴趣,我发现 discussion 正是关于 SENDRECV
-s 可能死锁的问题有时。
术语"thread"在这里有误导性,你应该谈论MPI任务或MPI进程(两者是等价的)。
根本原因是标签不匹配。您使用标签 200
发送,但接收时使用标签 100
.
此外,您应该使用 istat
而不是 status
作为 MPI_Sendrecv()
的状态参数。
这是修复程序的方法
call MPI_SENDRECV(foo, 1,&
& MPI_INTEGER, mpi_sendto, 200,&
& bar, 1,&
& MPI_INTEGER, mpi_recvfrom, 200,&
& MPI_COMM_WORLD, istat, ierr)