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

时间:2012-05-14 19:48:19

标签: python mpi interaction

我想以某种方式触发执行 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)

1 个答案:

答案 0 :(得分:5)

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

1)在您的MPI作业中将Python二进制文件作为等级0插入。为了将其排除在参与mpibinary的集体行动之外,您必须建立一个排除0级的子通信员,并将其用于mpibinary中的所有进一步集体通信。第一步是简单的部分。在Open MPI中你会这样做:

mpirun --hostfile hosts -np 1 pythonbinary args : -np 32 mpibinary args

这称为MPMD(多个程序多个数据)启动,它将启动pythonbinary的一个副本,该副本将成为等级0,并且还将成为等级为1的等级为2的mpibinary的32个副本, ......排名第32位(总共33个进程)。其他MPI实现也为MPMD发布提供了非常类似的机制。然后你使用MPI_Comm_split()来创建一个不包含Python程序的新通信器。拆分通信器是一项集体操作。这就是为什么你必须在Python代码和C ++应用程序中调用它。 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);

通过使用rank作为关键字,可以保证c_comm中的进程顺序与分割前​​的顺序相同,即来自MPI_COMM_WORLD的等级1将成为等级c_comm中的0,等级2将成为等级1,等等。

从现在开始,C ++应用程序可以像往常一样使用c_comm来执行集合操作。为了在Python和C ++代码之间进行通信,您仍然必须使用MPI_COMM_WORLD,并且Python代码仍然在其中排名为0.

2)使用MPI-2流程管理工具。首先,您将运行仅包含Python二进制文件的MPI作业:

mpirun --hostfile hosts -np 1 pythonbinary args

然后Python二进制文件将使用MPI_Comm_spawn()直接生成其他MPI二进制文件,并使用所需数量的新进程。新生成的流程将拥有自己的MPI_COMM_WORLD,您无需使用MPI_Comm_split()。此外,spawn操作将建立一个相互通信器,允许Python代码将消息发送到MPI应用程序的其他部分。


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

请注意,您只需要向Python脚本添加一些MPI调用,例如MPI_InitMPI_FinalizeMPI_Comm_split以及相关的MPI_Send / MPI_Recv。你不需要使它平行。 MPI非常通用,它不仅可以用于并行工作共享,还可以用作通用消息传递框架。但请注意,Python绑定应使用与程序其余部分相同的MPI库。

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