【问题标题】:Fortran MPI_Isend and MPI_IrecvFortran MPI_Isend 和 MPI_Irecv
【发布时间】:2020-03-09 17:51:04
【问题描述】:

我对 MPI_Isend 和 MPI_Irecv 有疑问:接收向量永远不会正确发送。 代码是用 Fortran 编写的。

每个进程都有许多我想向其发送一些值的接触进程。我要发送的值由 4 个向量组成,这些向量属于每个进程称为 variables 的类型。

这是我使用的代码:

program isend_test
use mpi

real, dimension(:,:,:), allocatable :: receivedValues
real, dimension(:,:), allocatable :: sendReals
integer, dimension(:,:), allocatable :: requestSend
integer, dimension(:,:), allocatable :: requestReceive
integer, dimension(:), allocatable :: neighbours
integer, dimension(mpi_status_size) :: status
integer :: ierr, currentNeighbour, k, me, nTasks, nValues, nNeighbours, addedNeighbours

call MPI_init(ierr)

call MPI_COMM_RANK(MPI_COMM_WORLD, me, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, nTasks, ierr)

nNeighbours = 2

! Only 3 values for each variable to keep it simple
nValues = 3

allocate(receivedValues(nNeighbours,4,nValues))
allocate(sendReals(4,nValues))
allocate(requestSend(4,nNeighbours))
allocate(requestReceive(4,nNeighbours))
allocate(neighbours(2))

receivedValues = -9999

! Initializing neighbours - Every process is adjacent to every other process in this example
addedNeighbours = 0
do j = 0,2
    if (j == me) then
        cycle
    endif
    addedNeighbours = addedNeighbours + 1
    neighbours(addedNeighbours) = j
enddo

! fill in some values to send
do j = 1,4
   do i=1,nValues
      sendReals(j,i) = j + 10*me + 100*i
   enddo
enddo

do j = 1,4
    do i = 1,nNeighbours
        call mpi_isend(sendReals(j,:), nValues, mpi_real, neighbours(i), j, MPI_COMM_WORLD, requestSend(j,i), ierr)
        call mpi_irecv(receivedValues(i, j, :), nValues, mpi_real, neighbours(i), j, MPI_COMM_WORLD, requestReceive(j,i), ierr)
    enddo
enddo


do j = 1,4
    do i = 1,nNeighbours
        call mpi_wait(requestSend(j,i), status, ierr)
        call mpi_wait(requestreceive(j,i), status, ierr)
    enddo
enddo

write(*,*)receivedValues

call MPI_finalize(ierr)
end

我知道数据类型是正确的(它们与MPI_SendMPI_Recv 一起使用)并且邻居和标签的整体匹配也是正确的,因为代码运行正确。但是,如果我在同步之前在开头设置receivedValues = -9999,则值不会更改。

我知道代码可以更有效地完成,但我做了很多更改以找到错误但没有成功......有人知道吗?这可能是缓冲区的问题,我只是找不到它......

顺便说一句:发送和接收sendReals(j,1)neighbours(i), j, 1) 也不起作用...

【问题讨论】:

  • 您可能已经知道您的代码有不匹配的括号,并且很难按原样编译。 StackOverflow 提倡使用 MCVE 公式化的问题,所以请修复代码“C”的完整性,以便编译无错误并重现声称的问题,否则“V"-erfiabilty 不满足。
  • 你有 4 * nNeighbours isend/irecv 对,但只有 nNeighbour 等待对,所以你的程序不可能是正确的 - 每个异步通信都必须有相应的等待,如果不是,你的程序不是正确。
  • @user3666197:你是对的,对不起。我修改了我的代码,使其更易于阅读,但在此过程中犯了一些错误。谢谢提醒。
  • @Ian Bush:这很尴尬,一个非常明显的错误。谢谢你。如果这不能解决此问题,我将再次发布完整版本。
  • 你也可以看看 mpi_waitall 这会稍微简化代码

标签: parallel-processing fortran mpi fortran90 openmpi


【解决方案1】:

接收缓冲区在内存中不连续(因为 Fortran 是主要列)

mpi_irecv(receivedValues(i, j, :)

所以这只能在 MPI_SUBARRAYS_SUPPORTED.true. 时起作用(并且它不在 Open MPI 中,可能是 MPICH 和 mpi_f08 绑定的情况)。

您不仅会得到不正确的数据,而且很可能会导致静默数据损坏。

您可以重新排序receivedValues 数组,或使用派生数据类型并将receivedValues(i,j,1) 用作接收缓冲区。

【讨论】:

  • 这比预期的要容易,改变receivedValues 的顺序就成功了。非常感谢!
猜你喜欢
  • 2015-05-27
  • 1970-01-01
  • 2017-08-20
  • 2011-08-01
  • 2018-09-13
  • 2015-12-09
  • 2017-10-01
  • 2015-05-15
  • 2016-01-06
相关资源
最近更新 更多