目前我有一个Python程序(串行)通过subprocess.run调用C可执行文件(通过MPI并行)。但是,这是一个非常笨重的实现,因为它意味着我必须使用文件系统将一些非常大的数组从Python传递到C程序。我希望能够直接将数组从Python传递给C并返回。我认为ctypes是我应该使用的。据我了解,我将创建一个DLL而不是我的C代码中的可执行文件,以便能够与Python一起使用它。
但是,要使用MPI,您需要使用mpirun
/ mpiexec
启动程序。如果我只是使用dll中的C函数,这是不可能的,对吗?
有没有一种好方法为从dll调用的函数启用MPI?我发现的两种可能性是
mpirun
。我不确定这是否可行。一种可能性,如果你可以通过c程序等级0传递所有内容,那就是使用subprocess.Popen()
和stdin=subprocess.PIPE
以及python方面的communicate()
函数和c方面的fread()
。
这显然是脆弱的,但确实将一切都记在了内存中。此外,如果您的数据大小(您说它是),您可能必须将数据写入子进程中的子进程。另一种选择可能是使用exe.stdin.write(x)
而不是exe.communicate(x)
我创建了一个小例子程序
c代码(程序名为child):
#include "mpi.h"
#include "stdio.h"
int main(int argc, char *argv[]){
MPI_Init(&argc, &argv);
int size, rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
double ans;
if(rank == 0){
fread(&ans, sizeof(ans), 1, stdin);
}
MPI_Bcast(&ans, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
printf("rank %d of %d received %lf\n", rank, size, ans);
MPI_Finalize();
}
python代码(名为driver.py):
#!/usr/bin/env python
import ctypes as ct
import subprocess as sp
x = ct.c_double(3.141592)
exe = sp.Popen(['mpirun', '-n', '4', './child'], stdin=sp.PIPE)
exe.communicate(x)
x = ct.c_double(101.1)
exe = sp.Popen(['mpirun', '-n', '4', './child'], stdin=sp.PIPE)
exe.communicate(x)
结果:
> python ./driver.py
rank 0 of 4 received 3.141592
rank 1 of 4 received 3.141592
rank 2 of 4 received 3.141592
rank 3 of 4 received 3.141592
rank 0 of 4 received 101.100000
rank 2 of 4 received 101.100000
rank 3 of 4 received 101.100000
rank 1 of 4 received 101.100000
我尝试通过mpi4py使用MPI_Comm_connect()
和MPI_Comm_accept()
,但我似乎无法在python端工作。
由于大部分时间都花在多次调用的C
子例程上,并且您在资源管理器中运行,我建议采用以下方法:
通过以下命令立即启动所有MPI任务(假设您已分配n+1
插槽
mpirun -np 1 python wrapper.py : -np <n> a.out
您可能希望从MPI_Comm_split()
开始,以便仅为n
程序实现的C
任务生成通信器。然后你将定义一个“协议”,以便python包装器可以将参数传递给C
任务,并等待结果或将C
程序指向MPI_Finalize()
。
你不妨考虑使用一个内部通信器(第一组用于python,第二组用于C
),但这完全取决于你。 Intercommunicator语义可以被视为非直观的,因此如果您想要进入该方向,请确保您了解其工作原理。