如何通过cython将MPI通信器从python传递到C?

时间:2018-07-27 11:37:00

标签: python c mpi cython mpi4py

我正在尝试通过cython将MPI_Comm通信器句柄作为参数包装C函数。结果,我希望能够从python调用该函数,并将其传递给mpi4py.MPI.Comm对象。我想知道的是如何进行从mpi4py.MPI.CommMPI_Comm的转换。

为了演示,我使用一个简单的“ Hello World!”类型的函数:

helloworld.h

#ifndef HELLOWORLD
#define HELLOWORLD
#include <mpi.h>

void sayhello(MPI_Comm comm);

#endif

helloworld.c

#include <stdio.h>
#include "helloworld.h"

void sayhello(MPI_Comm comm){
    int size, rank;
    MPI_Comm_size(comm, &size);
    MPI_Comm_rank(comm, &rank);
    printf("Hello, World! "
           "I am process %d of %d.\n",
           rank, size);
}

我现在想像这样从python调用此函数:

from_python.py

import mpi4py
import helloworld_wrap

helloworld_wrap.py_sayhello(mpi4py.MPI.COMM_WORLD)

意味着mpirun -np 4 python2 from_python.py应该给出类似的内容:

  

你好,世界!我正在处理4之0。
  你好,世界!我是第1步,共4步。
  你好,世界!我是第2步,共4步。
  你好,世界!我正在处理3之4。

但是,如果我尝试通过cython来实现此目标,

helloworld_wrap.pyx

cimport mpi4py.MPI as MPI
cimport mpi4py.libmpi as libmpi

cdef extern from "helloworld.h":
   void sayhello(libmpi.MPI_Comm comm)

def py_sayhello(MPI.Comm comm):
    sayhello(comm)

和:

setup.py

import os
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

mpi_compile_args = os.popen("mpicc --showme:compile").read().strip().split(' ')
mpi_link_args    = os.popen("mpicc --showme:link").read().strip().split(' ')

ext_modules=[
    Extension("helloworld_wrap",
              sources            = ["helloworld_wrap.pyx", "helloworld.c"],
              language           = 'c',
              extra_compile_args = mpi_compile_args,
              extra_link_args    = mpi_link_args,
          )
]

setup(
  name = "helloworld_wrap",
  cmdclass = {"build_ext": build_ext},
  ext_modules = ext_modules
)

我收到以下错误消息:

  

helloworld_wrap.pyx:8:13:无法将Python对象转换为“ MPI_Comm”

表示无法将mpi4py.MPI.Comm转换为MPI_Comm。那么如何将mpi4py.MPI.Comm转换为MPI_Comm才能使包装器正常工作?

1 个答案:

答案 0 :(得分:2)

转换非常简单,因为一个mpi4py.MPI.Comm对象在内部存储一个MPI_Comm句柄作为成员ob_mpi 1 。因此,如果将helloworld_wrap.pyx的最后一行更改为通过comm.ob_mpi而不是comm,则模块将按预期进行编译和工作:

helloworld_wrap.pyx

cimport mpi4py.MPI as MPI
cimport mpi4py.libmpi as libmpi

cdef extern from "helloworld.h":
   void sayhello(libmpi.MPI_Comm comm)

def py_sayhello(MPI.Comm comm):
    sayhello(comm.ob_mpi)

令人惊讶的是,我没有找到任何相关文档,只是在研究sources of mpi4py.MPI.Comm时才意识到这一点。我不确定这是否是处理此问题的预期方式,但我无法使其正常工作。


1 实际上,如果mpi4py.MPI中的大多数对象(如果不是在C中为相应的MPI句柄建模的所有对象),都将相应的句柄作为成员ob_mpi