通过一个(非MPI)的Python脚本与MPI二进制文件交互

3
我希望通过一个(串行)Python脚本来触发某些由C++编写的MPI程序中的函数执行。在脚本开始时,这个Python脚本应该使用如下方式启动mpi程序:
subprocess.call(['mpirun','-np', '4', 'mpibinary', 'args' ])

我需要多次调用这个MPI程序的函数,并且希望避免为不同的输入重新启动程序,因为我必须重新初始化所有的数据结构,这是很耗费时间的。因此,我考虑在MPI程序空闲时外部触发一个函数。我认为可以通过文件IO来实现,即MPI程序的根排名在while(1)循环中监视某个文件,一旦其内容更改,它解析新内容通知其他排名并调用一个函数。是否有更优雅的解决方案?
最好的解决方案是有一个Python类,封装C++ MPI程序的重要函数,这样我就可以从Python中调用它们。
mpiprogram.superfunction(a,b)

1
不要使用观察文件变化的方式(这种方式似乎很脆弱),你可以使用命名管道或套接字从Python向根MPI排名发送命令。 - Greg Inozemtsev
谢谢回复。使用套接字当然比观察文件更“优雅”,但是所有这些提到的解决方案都需要编写大量的代理存根。我仍在寻找一些不那么耗时的东西。 - thisch
1个回答

5
也许最优雅的解决方案是将Python代码作为MPI应用程序的一部分。这样,它就能够直接发送数据(通过MPI消息)到MPI应用程序的其余部分,因为它将成为其中的一部分。这里有两种不同的方法:
1)将Python二进制文件插入到MPI作业的rank 0中。为了在mpibinary中排除它参与集体操作,您需要创建一个排除rank 0的子通信器,并将其用于mpibinary中的所有进一步的集体通信。第一步是容易的。在Open MPI中,您可以执行以下操作:
mpirun --hostfile hosts -np 1 pythonbinary args : -np 32 mpibinary args

这被称为MPMD(多程序多数据)启动,它将启动一个pythonbinary的副本作为rank 0,以及32个mpibinary的副本作为rank 1、rank 2等,直到rank 32(总共33个进程)。其他MPI实现也提供非常类似的MPMD启动机制。然后,您需要使用MPI_Comm_split()来创建一个不包括Python程序的新通信器。拆分通信器是一种集体操作。这就是为什么您必须在Python代码和C++应用程序中都调用它的原因。MPI_Comm_split()接受一个“颜色”和一个关键字,并根据不同的颜色将通信器拆分成多个子通信器。具有相同颜色的进程然后根据关键值进行排序。您最有可能想这样调用它:
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二进制文件。新生成的进程将拥有自己的,您不需要使用。此外,生成操作将建立一个相互通信器,使Python代码能够向MPI应用程序的另一部分发送消息。
在两种情况下,文件将包含所有可以执行MPI二进制文件的执行主机的定义。您还需要使用可用的Python MPI绑定之一。
请注意,您只需要向Python脚本中添加一些MPI调用,例如、、和相关的 / 。您不需要使其并行。MPI非常灵活,因为它不仅允许您将其用于并行工作共享,而且还可以用作一般的消息框架。但请注意,Python绑定应使用与程序的其余部分相同的MPI库。
另一种解决方案是使用一些消息排队库或文件池(这实际上是粗略的MQ实现)。

1)的意思是我需要修改mpibinary吗?谁应该调用MPI_Comm_split? - thisch
不幸的是,1)和2)都需要对您的MPI二进制文件进行轻微修改。方法2)需要比1)更少的修改。我扩展了答案,包括有关如何调用“MPI_Comm_split”的信息,因为评论长度的限制太紧了。 - Hristo Iliev

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