我需要为MPI::Isend拥有一个对应的MPI::Irecv吗?

10

这似乎是一个愚蠢的问题,但我似乎找不到明确的答案。

基本问题是,对于MPI::Isend是否需要对应MPI::Irecv?

也就是说,即使消息发送是非阻塞的,只要在重复使用发送缓冲区之前等待发送完成,我是否需要使用非阻塞接收和等待来接收已发送的缓冲区?

我的意思是,我想使用非阻塞发送来“做其他事情”,而消息正在发送中,但接收进程将立即使用缓冲区,因此我希望它们会阻塞,直到缓冲区真正被接收。

似乎我可以使用MPI :: Recv接收使用MPI :: Isend发送的消息,但我想知道是否有什么我错过了?

一些简单的伪代码:

  if( rank == 0 ){
   int r;
   for ( int i = 0; i < n; i++ ){

     // DO SOME STUFF HERE...

     request.Wait(status);
     request2.Wait(status);
     request3.Wait(status);

     r = i;
     memcpy( key, fromKey(i), ...);
     memcpy( trace, fromTrace(i), ...);

     request  = MPI::COMM_WORLD.Isend( &r, 1, MPI::INT, node, tag );
     request2 = MPI::COMM_WORLD.Isend( key, 10, MPI::INT, node, tag );
     request3 = MPI::COMM_WORLD.Isend( trace, nBytesTotal, MPI::BYTE, node, tag );

     // DO SOME MORE STUFF HERE.

   }
   r = -1;
   request  = MPI::COMM_WORLD.Isend( &r, 1, MPI::INT, node, tag );

   // Carry on ...

  } else {

   int r = -1;
   MPI::COMM_WORLD.Recv( &r, 1, MPI::INT, 0, tag, status );
   while( r >= 0 ){

     MPI::COMM_WORLD.Recv( &key, 10, MPI::INT, 0, tag, status );
     memcpy( saveKey, key, ...);

     MPI::COMM_WORLD.Recv( &trace, nBytesTotal, MPI::BYTE, 0, tag, status );
     memcpy( saveTrace, trace, ...);

     MPI::COMM_WORLD.Recv( &r, 1, MPI::INT, 0, tag, status );
  }

这里的答案可能会引起您的兴趣:https://dev59.com/y2DVa4cB1Zd3GeqPgcN1 - dx_mrt
3个回答

19

不,你可以自由地在通信的两端混合使用阻塞和非阻塞MPI操作。阻塞与MPI调用何时返回控制给您的代码没有关系,而与传输的消息内容无关。

每个MPI消息都携带有一个“信封”,其中包含它的源地址、目标地址、标签和通信器。要成功接收消息,你的接收操作只应该匹配它的信封。
信封并不指定消息的发送方式 - 它是通过阻塞还是非阻塞操作发送的,是同步发送 (MPI_Ssend) 还是缓冲发送 (MPI_Bsend)。唯一的例外是所谓的 "就绪模式" 发送,它是通过 MPI_Rsend()MPI_Irsend() 启动的,它要求匹配的接收操作已经被发布,否则消息将无法被传递。

这就是为什么 MPI 标准中使用术语 "匹配接收操作" 而不是类似于 "相应接收函数" 的原因。


所以答案是“不,你不需要为MPI :: Isend拥有相应的MPI :: Irecv”。这就是我想的。如果情况不是这样,我会感到惊讶的。感谢您提供详细信息。 - BernieP

2

没问题,发送/接收的“类型”(或者你想怎么称呼它们)不需要匹配。


那正是我所想的。如果情况不是这样,我会感到惊讶的。我猜我真的很担心任何实现在那种情况下可能会做一些奇怪的事情。 - BernieP

1
无论您使用什么send/recv,实现都很重要。您必须注意代码中的阻塞点。例如,在使用阻塞通信时,您必须小心发送和接收调用,例如查看此代码:
 if(rank==0)
 {
 MPI_Send(x to process 1)
 MPI_Recv(y from process 1)
 }
 if(rank==1)
 {
 MPI_Send(y to process 0);
 MPI_Recv(x from process 0);
 }

在这种情况下会发生什么? 进程0向进程1发送x并阻塞,直到进程1接收到x,进程0向进程0发送y并阻塞,直到进程0接收y,但是进程0被阻塞了,因此进程1会无限期地阻塞,直到您杀死这2个进程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接