非阻塞调用何时需要 MPI_Wait?

计算科学 并行计算 mpi C
2021-12-16 21:16:15

我希望这不是太离题——我已经在 SO 上问过了,但我希望我能在这里得到更好的答案!


我对何时应该调用 MPI_Wait(或其他变体,例如:MPI_Waitall、MPII_Waitsome 等)感到有些困惑。考虑以下情况:(注:伪代码)

情况1)

MPI_Isend (send_buffer, send_req);    
// Do local work
MPI_Probe (recv_msg);
MPI_Irecv (recv_buffer, recv_req);
// wait for msgs to finish
MPI_Wait (recv_req);   // <--- Is this needed?
MPI_Wait (send_req);   // <--- How about this?

所以我的困惑源于MPI_Probe这种情况。由于这是一个阻塞调用,这是否意味着它会阻塞调用者直到收到消息?如果是这种情况,那么我认为 MPI_Waits 在这里是不必要的。

下面的案例呢?

案例(2)

MPI_Isend (send_buffer, send_req);    
// Do local work
MPI_Probe (recv_msg);
MPI_Recv (recv_buffer);
// wait for msgs to finish
MPI_Wait (send_req);   // <--- Is this necessary?

与第一种情况类似,但MPI_Irecv被替换为阻塞版本。在这种情况下,消息肯定是在MPI_Wait被调用的时候收到的,这意味着MPI_Isend必须已经完成......

同样作为一个单独的问题,当我们说MPI_Probe阻塞时,我们的意思是什么?它会阻塞直到进程收到所有消息,还是仅阻塞直到收到“元数据”(例如消息大小、发件人等级等)?换句话说,MPI_Probe+MPI_IrecvMPI_Probe+更好MPI_Recv吗?

4个回答

比尔回答了第一部分,所以我只回答第二个问题。如果 MPI 发送在可以安全地修改发送缓冲区之前不返回,则它是阻塞的;如果在接收缓冲区包含新接收的消息之前它不返回,则接收是阻塞的。实际上,在缓冲发送之外(感谢 Hristo Iliev),这意味着在返回之前可能需要通信。例如,MPI_Send正在阻塞,因为它在消息被缓冲或发送之前无法完成。实现通常会“急切地”缓冲短消息,在这种情况下MPI_Send似乎会立即返回。这意味着代码如下所示:

MPI_Send(&x,count,MPI_INT,(rank+1)%size,1,comm);
MPI_Recv(&y,count,MPI_INT,(size+rank-1)%size,1,comm,MPI_STATUS_IGNORE);

预计对于大消息会死锁,尽管对于足够小的消息它可能会成功。非阻塞发送和接收MPI_Request必须在访问/修改缓冲区之前完成的返回。

有些操作与发送和接收有点不同。MPI_Probe正在阻塞,因为它在找到消息之前不会返回,尽管该消息还没有被接收到。 MPI_Iprobe是非阻塞的,即使没有消息它也总是返回。

MPI_Probe允许您在不实际接收消息的情况下测试消息。必须使用适当的通信完成函数(如 MPI_Wait 和朋友)完成所有非阻塞通信,否则运行时不会释放与通信相关的内部资源,从而导致资源泄漏和其他问题。例如,在通过适当的完成调用完成通信之前,您可能不会将发送消息缓冲区用于其他任何事情。

每次MPI_Request在 MPI 函数中使用 an 时,您要么必须等待它完成使用任何MPI_Wait函数,要么继续使用MPI_Test它,直到标志返回非零。

这包括所有以MPI_I(非阻塞发送、接收和集合)开头的函数和取消某些非阻塞操作的函数,例如

int i = 0;
MPI_Request req = MPI_REQUEST_NULL;
MPI_Isend( &i, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &req );
MPI_Cancel( &req );
MPI_Wait( &req, MPI_STATUS_IGNORE ); // you have to wait

您是对的,在某些情况下,您可以通过推理来确定IsendorIrecv已经结束,因此您不必在Wait语义上进行。在这种情况下,等待的唯一原因是“I”操作分配了一个MPI_Request对象,而您需要释放它。所以等待可以防止内存泄漏。您还可以使用MPI_Request_free来释放请求对象。