目前我有一个Python程序(串口)通过subprocess.run调用C可执行文件(通过MPI并行)。但是,这是一个非常笨重的实现,因为它意味着我必须使用文件系统将一些非常大的数组从Python传递到C程序。我希望能够直接将数组从Python传递给C并返回。我认为ctypes是我应该使用的。据我了解,我会在我的C代码中创建一个dll而不是可执行文件,以便能够将它与Python一起使用。
但是,要使用MPI,您需要使用class A:
@classmethod
def key_fn(cls, id):
raise NotImplementedError('')
@classmethod
def load_all(cls):
yield from db_fetch_prefix(cls.key_fn('')):
class B(A):
@classmethod
def key_fn(cls, id):
return f'/keys/{id}'
# how do I make sure B.key_fn is called here?
B.load_all()
/ mpirun
启动该计划。如果我只是使用dll中的C函数,这是不可能的,对吗?
是否有一种很好的方法可以为从dll调用的函数启用MPI?我发现的两种可能性是
使用mpi4py并行启动python程序,然后将MPI_COMM_WORLD传递给C函数(按照此帖How to pass MPI information to ctypes in python)
以某种方式初始化并在函数内部生成进程而不使用mpiexec
。我不确定这是否可行。
答案 0 :(得分:0)
一种可能性,如果你可以通过c程序等级0传递所有内容,那就是在subprocess.Popen()
使用stdin=subprocess.PIPE
并在python端使用communicate()
函数并{{1在c方面。
这显然是脆弱的,但确实将一切都记在了内存中。此外,如果您的数据大小(您说它是),您可能必须将数据写入子进程中的子进程。另一种选择可能是使用fread()
而不是exe.stdin.write(x)
我创建了一个小示例程序
c代码(程序名为child):
exe.communicate(x)
python代码(名为driver.py):
#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();
}
结果:
#!/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)
我尝试通过mpi4py使用> 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
和MPI_Comm_connect()
,但我似乎无法在python端运行。
答案 1 :(得分:0)
由于大部分时间花在多次调用的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语义可以被视为非直观的,因此如果你想进入那个方向,请确保你理解它是如何工作的。