在上一篇中我们介绍了在 mpi4py 中包装和调用 C 语言 MPI 程序的方法。在实际应用中直接使用 Python/C API 编写 Python 扩展模块是比较麻烦的,要求对 Python/C API 非常熟悉才能很好地运用,更常用的做法是使用像 SWIG 这样的工具来包装 C/C++ 程序文件,下面我们介绍用 SWIG 包装 C 语言 MPI 程序以供 mpi4py 调用的方法。
SWIG (Simplified Wrapper and Interface Generator) 是一个包装和接口生成器工具,可以为C/C++程序构建生成各种脚本语言的调用接口,这样就可以通过脚本语言来直接调用C/C++编写的程序。使用 SWIG 包装 C/C++ 程序是比较简单的,只需要编写一个 .i 接口文件,在其中声明调用接口和完成所需的类型映射即可。如要了解更多,可参考完整的 SWIG 使用文档,此处我们只以以下简单的例子来展示用 SWIG 包装 C 语言 MPI 程序以供 mpi4py 调用的方法。
SWIG 的 .i 接口文件有点类似于 C/C++ 的头文件,最简单的包装 C 语言方法是直接将一段 C 程序代码放入 .i 接口文件的 %{ %} 之间,并在外面完成类型映射及声明要导出的函数接口。
我们以上一篇中用到的 C 语言函数 sayhello 为例,我们将此函数放入接口文件 helloworld.i 的 %{ %} 之间,并在下面声明其函数原型,因为其参数为一个 MPI_Comm 类型的通信子,还需要指明一个由 mpi4py 中的通信子到 MPI_Comm 类型的映射,这个映射在 mpi4py 软件中包含的 mpi4py.i 中定义,因此需要 include mpi4py/mpi4py.i。完整的接口文件如下:
/* helloworld.i */
%module helloworld
%{
#define MPICH_SKIP_MPICXX 1
#define OMPI_SKIP_MPICXX 1
#include <mpi.h>
#include <stdio.h>
void sayhello(MPI_Comm comm) {
int size, rank;
char pname[MPI_MAX_PROCESSOR_NAME]; int len;
if (comm == MPI_COMM_NULL) {
printf("You passed MPI_COMM_NULL !!!\n");
return;
}
MPI_Comm_size(comm, &size);
MPI_Comm_rank(comm, &rank);
MPI_Get_processor_name(pname, &len)