如何将Python与使用MPI的C程序进行交互

时间:2018-02-24 21:42:34

标签: mpi

目前我有一个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。我不确定这是否可行。

2 个答案:

答案 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语义可以被视为非直观的,因此如果你想进入那个方向,请确保你理解它是如何工作的。