我在 Open MPI 用户列表上回复了您,但也会在此处发布,以防其他人发现它有用。我相信 Jeff Squyres 已经在 Open MPI 邮件列表中回答了您的问题,或者至少暗示了可能存在的问题。MPI 消息按照它们发送的顺序被接收,但只在特定的(标签、通信器)元组内。这基本上意味着:
- 在同一个通信器中,如果它们带有不同的标签,您可能会收到乱序的消息;
- 如果它们在不同的上下文(通信器)中通信,则带有相同标签的消息可能会被乱序接收。
但这里有一个问题:如果尚未发布发送操作,您将无法收到消息。如果您有两个连续的发送操作,您必须确保第一个不会永远阻塞。标准的 MPI 发送操MPI_Send
作可以以多种方式实现(标准没有具体说明如何),但在大多数 MPI 实现中,它的行为类似于非常小的消息的缓冲发送和大型消息的同步发送。如果您的发件人进程中有以下两个调用:
MPI_Send(largedata, largecount, MPI_INT, dest, tag1, MPI_COMM_WORLD);
MPI_Send(smalldata, smallcount, MPI_INT, dest, tag2, MPI_COMM_WORLD);
可能会发生第一个MPI_Send
实际上表现为同步的,即除非匹配的接收操作发布在接收方一侧,否则它不会返回。假设您的接收者代码是:
MPI_Probe(src, tag2, MPI_COMM_WORLD, &status);
MPI_Recv(largedata, largecount, MPI_INT, src, tag1, MPI_COMM_WORLD, &status);
这很可能会死锁,因为这MPI_Probe
是一个阻塞调用,即它不会在匹配的发送被发布之前返回,即第二个MPI_Send
必须执行,这只会在第一个发送返回后发生,但它不会发生,除非MPI_Recv
在接收者被执行...我想你明白了
为了防止死锁,您可以修改发件人的代码以使用非阻塞发送:
MPI_Request req;
MPI_Isend(largedata, largecount, MPI_INT, dest, tag1, MPI_COMM_WORLD, &req);
MPI_Send(smalldata, smallcount, MPI_INT, dest, tag2, MPI_COMM_WORLD);
MPI_Wait(&req, MPI_STATUS_IGNORE);
使用非阻塞操作,发送调用立即返回,操作在后台继续,因此第二次发送将在此之后立即执行。现在会有两条待处理的消息,它们可以按任何顺序接收,因为它们带有不同的标签。