如何在MPI中安全地切换到另一个通信器

如何在MPI中安全地切换到另一个通信器,mpi,mpi4py,Mpi,Mpi4py,我正在使用MPI(实际上是mpi4py)编写一个应用程序。应用程序可以使用MPI\u Comm\u spawn()(在所有当前进程上统称)生成一些新进程,父组/通信器中的某些节点可以向子组/通信器中的某些节点发送数据,反之亦然。(注意,MPI\u Comm\u spawn()和数据发送/接收发生在不同的线程中,这两个线程的功能[还有其他与此问题不直接相关的功能,因此我没有描述]和性能。) 由于MPI\u Comm\u spawn()函数可能会被多次调用,并且我希望所有节点都可以相互通信,因此我目

我正在使用MPI(实际上是mpi4py)编写一个应用程序。应用程序可以使用
MPI\u Comm\u spawn()
(在所有当前进程上统称)生成一些新进程,父组/通信器中的某些节点可以向子组/通信器中的某些节点发送数据,反之亦然。(注意,
MPI\u Comm\u spawn()
和数据发送/接收发生在不同的线程中,这两个线程的功能[还有其他与此问题不直接相关的功能,因此我没有描述]和性能。)

由于
MPI\u Comm\u spawn()
函数可能会被多次调用,并且我希望所有节点都可以相互通信,因此我目前计划使用
MPI\u Intercomm\u merge()
将两个组(父组和子组)合并到一个内部通信程序中,然后通过新的内部通信程序发送数据(下一个
MPI\u Comm\u spawn()
将发生在新的内部通讯器上)

但是,由于生成和合并过程发生在程序运行期间,因此将有一些数据已经通过旧的通信器发送(但可能尚未被dest接收)。我如何才能安全地从旧的通信器切换到新的通信器(例如,能够在某个点删除旧的通信器)在性能损失最小的情况下,
MPI\u Comm\u merge()
是我所知道的确保所有进程都可以互相发送数据的唯一方法(因为如果我们不合并,下次调用
MPI\u Comm\u merge()
,一些进程就不能直接互相发送数据),我不介意将其更改为另一种方法,只要它运行良好

例如,在下图中,流程A、B、C是初始流程(
mpiexec-np 3
),D是衍生流程:

A和B将向C发送连续数据;在发送期间,D生成;然后C向D发送数据。假设旧的通讯器A、B和C使用的是
comm1
,合并的内部通讯器是
comm2

我想要实现的是最初通过
comm1
发送数据,然后(所有进程)在产生D之后切换到
comm2
。缺少的是一种机制,可以知道C何时可以安全地从
comm1
切换到
comm2
以接收来自a和/或B的数据,然后我可以安全地调用
MPI\u Comm\u free(comm1)
。 在切换时,只需通过
comm1
发送一个特殊标记将是最后一个选项,因为C不知道有多少进程将向其发送数据。它知道有多少进程组将向其发送数据,所以这可以通过引入本地领导者来实现(但我想知道其他选项)。
由于
A
B
C
是并行处理的,
send
/
recv
spawn
发生在不同的线程中,因此调用
MPI\u Comm\u spawn()时无法保证没有挂起的数据
。例如,如果我们想象
A
B
处理
发送
C
以相同的速率处理
recv
,当它们调用
comm_spawn
时,
C
只从
A
B
接收了一半的数据,因此我们还不能在
C
上删除
comm1
,但我们已经完成了等待,直到
C
comm1
接收到所有挂起的数据(消息数量未知)

MPI或mpi4py是否提供了任何机制(例如错误代码或异常)来实现这一点

顺便说一下,如果我的方法明显不好,或者我误解了MPI\u Comm\u free()的作用,请指出。

(我的理解是,
MPI\u Comm\u free()
不是一个集体调用;在调用
MPI\u Comm\u free(comm1)
之后,在调用
MPI\u Comm\u free(comm1)
节点上,不再允许对
comm1
发送/接收调用。因此基本上,
C
调用
MPI\u Comm\u(…,MPI通信自身…)

为什么不使用
{A,B,C}
调用
MPI\u Comm\u spawn(…,comm1,…)

MPI\u intercom\u merge()
是一个集体操作,因此您需要以某种方式“同步”任务,所以为什么不在
MPI\u Comm\u spawn()之前“同步”它们呢


那么,切换到新的通信器是微不足道的

我应该说得更清楚:我正在集体执行
MPI\u Comm\u spawn()
,但这是在另一个线程上进行的(与数据发送/接收线程上发生的情况不同)。因此,无法保证当一个进程完成
MPI\u Comm\u spawn()时
,数据传输已经完成。也就是说,如果我们想象
A
B
进程
发送
C
进程
接收
的速率相同,当他们调用
comm\u sprown
时,C只从
A
B
接收了一半的数据。