MPI缓冲发送/接收顺序

3
我是一个有用的助手,可以为您翻译文本。
我正在使用MPI(使用fortran语言,但是问题更具体地涉及MPI标准而不是任何给定的语言),并特别使用带缓冲的发送/接收函数isend和irecv。现在,如果我们想象以下场景:
进程0:
isend(stuff1, ...)
isend(stuff2, ...)

步骤1:

wait 10 seconds
irecv(in1, ...)
irecv(in2, ...)

如果在所有情况下使用相同的标签,消息是否按照发送顺序传递给进程1?也就是说,我可以确定in1 == stuff1和in2 == stuff2吗?

2个回答

8
是的,消息是按发送顺序接收的。这被标准描述为非超车消息。有关详细信息,请参阅MPI标准部分,以下是摘录:
引用:

顺序消息不超车:如果发送方连续向同一目标发送两条消息,并且两条消息都与相同的接收匹配,则如果第一条消息仍在等待,则此操作无法接收第二条消息。如果接收方连续发布两次接收,并且两次接收都与相同的消息匹配,则如果第一次仍然未完成,则第二个接收操作也无法满足此消息。这要求便于将发送与接收匹配。它保证在进程单线程且未在接收中使用通配符MPI_ANY_SOURCE时,消息传递代码是确定性的。(稍后描述的某些调用,例如MPI_CANCEL或MPI_WAITANY,是非确定性的其他来源。)


2

是的和不是的。

如果在所有情况下使用相同的标记,我能确定in1 == stuff1和in2 == stuff2吗?

是的。 发送和接收之间存在确定性的一对一关系,可以将正确的输入放入正确的接收缓冲区中。 此行为由标准保证,并由所有MPI实现强制执行。

不是的。 内部消息进展的确切顺序以及接收方缓冲区填充的确切顺序有些黑匣子,特别是在使用多个正在进行的缓冲区的RDMA样式消息传输时(例如InfiniBand)。

如果您的代码使用多个线程,并检查缓冲区以确定完整性(例如等待位被切换),而不是使用MPI_Test或MPI_Wait,则可能会导致消息无序到达(但在正确的缓冲区)。

如果您的代码依赖于在接收方先填充in1 = stuff1,然后再填充in2 = stuff2,并且有一个单独的发送排名用于两个消息,则使用MPI_Issend(非阻塞同步发送)将保证消息按顺序recv'd。 如果您需要保证从多个发送排名接收的多个recv的缓冲区填充顺序,则在每个revc之间需要某种阻塞调用(例如MPI_Recv,MPI_Barrier,MPI_Wait等)。


2
必须减1,因为我无法完全相信你“是和否”回答中的“否”部分... 用你提出的方式来“检查完成”是荒谬的。同样地,如果我问你“x = 42; printf("%d", x);是否保证打印42?”你也可以说“是和否;不是因为如果你在调试器中逐步执行并改变了x的值,那就不会打印42。” - j_random_hacker
2
@j...我所支持的三位用户中发生了所描述的情况。他们的工作有多线程排名,其中一个MPI通信线程。其他线程正在与硬件控制器交互。硬件控制器线程正在检查缓冲区的最后一位以确定消息完成。当他们从TCP转移到IB时,出现了消息乱序到达问题。这更像是“编译器优化”,而不是你给出的调试器示例。织物管理器保留了缓冲区顺序,但优化了实际传输顺序。 - Stan Graves
1
我很震惊。(这就是MPI_Test()的作用!)但如果有3个用户弄错了,那么你帖子中的信息就很有价值。所以,如果你编辑一下并加上一个大大的“但不要这样做,这很愚蠢”之类的话,我会点赞。 - j_random_hacker
我更关心广义的想法,而不是具体的例子:使用RDMA时,接收方缓冲区填充的确切顺序有点像黑匣子。使用MPI_Test或MPI_Wait(或所有/任何变体)是确定消息传输何时完成的“前门”方法。我在我的示例中特别提到了多线程情况。从多个线程调用MPI会引入性能损失。从一个线程使用MPI_Test / Wait检查另一个线程中消息传输的完整性可能不合适。 - Stan Graves
1
如果您需要在不同的线程中进行MPI调用,那么您需要在不同的线程中进行MPI调用,并且您必须承担使用线程安全MPI实现的性能惩罚--否则,就像您展示的那样,行为是未定义的。我不明白为什么您不想明确这一点,但好吧。 - j_random_hacker

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