如何使用MPI_Probe循环探测接收多条不同MPI消息?
问题根因
你的代码无法正常运行的核心原因:MPI_Probe 是仅做队列探测、不消费消息的接口——只要匹配规则命中的第一条消息还没被MPI_Recv从接收队列取出,后续所有匹配规则一致的MPI_Probe调用,都会反复返回这同一条消息的元数据,根本无法访问队列中排在后面的第二条消息。
你提到的「发送-接收-发送-接收」交替模式虽然可以跑通,但会引入额外的同步等待开销,通信效率更低,不是最优解。下面按改动成本和性能优先级给出可行方案:
可选解决方案
方案1:最小改动,探测一条就接收一条
完全不需要修改发送端逻辑,只要调整接收端执行顺序即可:
- 第一次调用
MPI_Probe匹配到队列首条消息,从status中读取tag存为size1后,立刻调用MPI_Recv把这条消息从队列中取走 - 第一条消息被消费后,再调用第二次
MPI_Probe,此时自然能探测到第二条消息,读取tag存为size2后再接收第二条消息即可
参考代码(Fortran):
! 接收端逻辑 call MPI_Probe(sender, MPI_ANY_TAG, COMM, status, error) size1 = status(MPI_TAG) ! 探测到第一条消息后立刻接收,匹配对应的数据类型和tag call MPI_Recv(message, size1, MPI_INT, sender, size1, COMM, status, error) ! 第一条消息消费完成,才能探测到第二条 call MPI_Probe(sender, MPI_ANY_TAG, COMM, status, error) size2 = status(MPI_TAG) call MPI_Recv(message2, size2, MPI_DOUBLE, sender, size2, COMM, status, error) actual_size = MIN(size1, size2)
注意:把数组长度存在消息tag中传递的写法存在硬限制:多数MPI实现的tag取值上限为MPI_TAG_UB(通常为32767),如果数组长度超过该值会直接触发运行错误,不适合传递大长度值。
方案2:标准动态消息实现,不依赖tag传长度
这是MPI动态长度消息的通用最优实现,性能和鲁棒性都更好:
- 发送端不需要把长度塞到tag里,给两类消息提前约定固定的区分tag即可,比如整型数组消息固定用tag=1,双精度数组消息固定用tag=2
- 接收端探测到消息后,直接调用
MPI_Get_count从status中读取消息的实际元素个数,不需要提前知道长度,也绕开了tag取值范围的限制
参考代码:
! 发送端逻辑 ! 两类消息用固定tag区分,tag值可以自行定义,只要不冲突即可 call MPI_Isend(message, size, MPI_INT, destination, 1, COMM, req1, error) call MPI_Isend(message2, size*3, MPI_DOUBLE, destination, 2, COMM, req2, error) ! 接收端逻辑,不需要严格按发送顺序接收也能正确匹配 call MPI_Probe(sender, 1, COMM, status, error) call MPI_Get_count(status, MPI_INT, size1, error) ! 直接读取消息实际长度 call MPI_Recv(message, size1, MPI_INT, sender, 1, COMM, status, error) call MPI_Probe(sender, 2, COMM, status, error) call MPI_Get_count(status, MPI_DOUBLE, size2, error) call MPI_Recv(message2, size2, MPI_DOUBLE, sender, 2, COMM, status, error) actual_size = MIN(size1, size2)
关于交替收发模式的说明
「发送-接收-发送-接收」的交替模式本质是把两次并行的通信串行化,会多一倍的通信往返等待开销,带宽利用率低,除非业务逻辑有强同步要求,否则不建议采用。
内容的提问来源于stack exchange,提问作者Daniel Bar
相关产品推荐
相关产品推荐

