通过(非MPI)python脚本与MPI二进制文件交互

通过(非MPI)python脚本与MPI二进制文件交互,python,mpi,interaction,Python,Mpi,Interaction,我想通过某种方式触发MPI程序(用C++编写)的某些函数的执行,例如(串行)python脚本。此python脚本应在开始时启动mpi程序,例如 subprocess.call(['mpirun','-np', '4', 'mpibinary', 'args' ]) 我需要多次调用这个MPI程序的一个函数,并且我希望避免为不同的输入重新启动程序,因为我必须重新初始化我的所有数据结构,这是非常昂贵的。因此,我考虑过在MPI程序空闲时从外部触发一个函数。我认为这可以通过文件IO实现,也就是说,MPI

我想通过某种方式触发MPI程序(用C++编写)的某些函数的执行,例如(串行)python脚本。此python脚本应在开始时启动mpi程序,例如

subprocess.call(['mpirun','-np', '4', 'mpibinary', 'args' ])
我需要多次调用这个MPI程序的一个函数,并且我希望避免为不同的输入重新启动程序,因为我必须重新初始化我的所有数据结构,这是非常昂贵的。因此,我考虑过在MPI程序空闲时从外部触发一个函数。我认为这可以通过文件IO实现,也就是说,MPI程序的根列组在while(1)循环中观察某个文件,一旦其内容发生变化,它就会解析新内容,通知其他列组并调用函数。有没有更优雅的方法来解决我的问题

最好的解决方案是有一个Python类,它封装了C++ MPI程序的重要功能,以便我可以用Python调用它们。

mpiprogram.superfunction(a,b)

也许最优雅的解决方案是将Python代码作为MPI应用程序的一部分。然后,它将能够直接(通过MPI消息)向MPI应用程序的其余部分发送数据,因为它将是MPI应用程序的一部分。这里有两种不同的方法:

1) 将Python二进制文件作为秩0插入MPI作业中。为了将其排除在
mpibinary
中的集体操作之外,您必须创建一个排除秩0的子通信程序,并将其用于
mpibinary
中的所有进一步集体通信。第一步是简单的部分。在Open MPI中,您将执行以下操作:

mpirun --hostfile hosts -np 1 pythonbinary args : -np 32 mpibinary args
这被称为MPMD(多程序多数据)启动,它将启动一个将成为秩0的
pythonbinary
副本,以及32个将成为秩1、秩2的
mpibinary
。。。高达32级(共33个流程)。其他MPI实现也为MPMD启动提供了非常类似的机制。然后使用
MPI\u Comm\u split()
创建一个不包含Python程序的新通信器。拆分通信器是一种集体操作。这就是为什么你必须在Python代码和C++应用程序中同时调用它。code>MPI_Comm_split()接受一个“颜色”和一个键,并根据不同的颜色将通信器拆分为多个子通信器。然后根据键值对具有相同颜色的进程进行排序。您很可能会这样称呼它:

在Python中:

python_comm = mpi.mpi_comm_split(mpi.MPI_COMM_WORLD, 0, 0)
在C++中:

int rank;
MPI_Comm c_comm;

MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_split(MPI_COMM_WORLD, 1, rank, &c_comm);
通过使用
等级
作为键,可以确保
CU comm
中的进程顺序与拆分前相同,即
MPI_comm
中的等级1将在
CU comm
中变为等级0,等级2将变为等级1,等等

<>从现在开始,C++应用程序可以使用CyCAMM进行集体操作。为了在Python和C++代码之间进行通信,你仍然必须使用<代码> MPIYCAMSULL ,Python代码仍然是排名0的。 2) 使用MPI-2过程管理设施。首先,您将运行仅由Python二进制文件组成的MPI作业:

mpirun --hostfile hosts -np 1 pythonbinary args
然后Python二进制文件将直接使用
MPI\u Comm\u spawn()
和所需数量的新进程生成另一个MPI二进制文件。新生成的进程将有自己的
MPI\u COMM\u WORLD
,您不需要使用
MPI\u COMM\u split()
。另外,spawn操作将建立一个内部通信程序,允许Python代码向MPI应用程序的其他部分发送消息


在这两种情况下,
hosts
文件将包含可以执行MPI二进制文件的所有执行主机的定义。您还需要使用一个可用的Python MPI绑定

请注意,您只需要向Python脚本添加一些MPI调用,如
MPI_Init
MPI_Finalize
MPI_Comm_split
和相关的
MPI_Send
/
MPI_Recv
。你不需要让它平行。MPI的用途非常广泛,它不仅允许您将其用于并行工作共享,还允许您将其用作通用消息传递框架。但是请注意,Python绑定应该使用与程序其余部分相同的MPI库


另一种解决方案是使用一些消息队列库或文件池(这实际上是一种粗糙的MQ实现)。

您可以使用命名管道或套接字将命令从Python.Thx发送到根MPI列组以获得响应,而不是查看文件中的更改(这似乎很脆弱)。使用套接字当然比查看文件更“优雅”,但上述所有解决方案都需要编写大量代理存根。我仍然在寻找一些不那么耗时的东西。1)是否意味着我需要修改MPI二进制文件?谁应该调用MPI_Comm_split?不幸的是,1)和2)都需要对MPI二进制文件稍作修改。方法2)需要的修改少于1)。我已经扩展了答案,包括如何调用
MPI\u Comm\u split
的信息,因为注释长度的限制太严格了。