在 C 语言中嵌入 mpi4py 程序

在上一篇中我们介绍了用 f2py 包装 Fortran 语言 MPI 程序以供 mpi4py 调用的方法,可以看到包装 C, C++,Fortran 等其它计算机语言的 MPI 程序供 mpi4py 调用是比较容易的,其实反过来将 mpi4py 程序嵌入其它计算机语言中也不难,下面我们将介绍在 C 语言程序中嵌入 mpi4py 程序的方法。

Python 与 C 之间的互操作在底层都是通过 Python/C API 实现的,要在 C 语言中嵌入 mpi4py 程序也是通过 Python/C API 的相关函数实现的。最简单的方法是使用函数 PyRun_SimpleString 直接执行一段 mpi4py 程序代码,不过需要注意的是要首先包含 mpi.h 和 Python.h 头文件,并初始化 MPI 和 Python 环境,等执行完 Python 程序后,记得要释放 MPI 和 Python 环境。举例如下:

/* helloworld.c */

#include 
#include 

const char helloworld[] = \
  "from mpi4py import MPI                                \n"
  "hwmess = 'Hello, World! I am process %d of %d on %s.' \n"
  "myrank = MPI.COMM_WORLD.Get_rank()                    \n"
  "nprocs = MPI.COMM_WORLD.Get_size()                    \n"
  "procnm = MPI.Get_processor_name()                     \n"
  "print (hwmess % (myrank, nprocs, procnm))             \n"
  "";

int main(int argc, char *argv[])
{
  MPI_Init(&argc, &argv);
  Py_Initialize();

  PyRun_SimpleString(helloworld);

  MPI_Finalize(); /* MPI should be finalized */
  Py_Finalize();  /* after finalizing Python */

  return 0;
}

可以使用类似下面的命令编译和生成可执行程序 helloworld (注意将其中的路径改成你的系统中实际的路径):

$ mpicc -I/path/to/python/include/python2.7 -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -o helloworld helloworld.c -L/path/to/python/lib/python2.7/config -lpthread -ldl -lutil -lm -lpython2.7 -Xlinker -export-dynamic

执行结果如下:

$ mpiexec -n 4 ./helloworld
Hello, World! I am process 1 of 4 on node2.
Hello, World! I am process 3 of 4 on node2.
Hello, World! I am process 2 of 4 on node2.
Hello, World! I am process 0 of 4 on node2.

也可以将要嵌入的 mpi4py 程序放入单独的文件,如 helloworld.py,然后使用 PyRun_SimpleFile 函数来执行它,如下:

# helloworld.py

from mpi4py import MPI


hwmess = 'Hello, World! I am process %d of %d on %s.'
myrank = MPI.COMM_WORLD.Get_rank()
nprocs = MPI.COMM_WORLD.Get_size()
procnm = MPI.Get_processor_name()
print (hwmess % (myrank, nprocs, procnm))
/* helloworld.c */

#include 
#include 

int main(int argc, char *argv[])
{
  const char *fname = "./helloworld.py";
  FILE *fp;

  MPI_Init(&argc, &argv);
  Py_Initialize();

  fp = fopen(fname, "r");
  PyRun_SimpleFile(fp, fname);

  MPI_Finalize(); /* MPI should be finalized */
  Py_Finalize();  /* after finalizing Python */

  return 0;
}

为了方便,我们也可以编写如下 Makefile 以简化编译操作(注意其中使用了在上一篇中介绍的 python-config 文件):

# Makefile

.PHONY: default build test clean

default: build test clean

PYTHON = python
PYTHON_CONFIG = ${PYTHON} ./python-config

MPICC   = mpicc
CFLAGS  = ${shell ${PYTHON_CONFIG} --cflags}
LDFLAGS = ${shell ${PYTHON_CONFIG} --ldflags}
build: helloworld
helloworld: helloworld.c
    ${MPICC} ${CFLAGS} -o $@ $< ${LDFLAGS}


MPIEXEC = mpiexec
NP_FLAG = -n
NP = 5
test: build
    ${MPIEXEC} ${NP_FLAG} ${NP} ./helloworld


clean:
    ${RM} -r helloworld

编译扩展库,执行程序及清理可以分别使用如下命令:

$ make build
$ make test
$ make clean

以上非常简单地介绍了在 C 语言中嵌入 mpi4py 程序的方法,更多的内容可以参考 Python/C API 文档。

前面我们所给出的各个例程一般都是在单台计算机上直接使用 mpiexec 或 mpirun 执行的,但是在实际应用中,对规模比较大的高性能计算任务,一般会提交到集群或超级计算机平台上进行计算。集群系统具有低成本、高性能的特性,提供了强大的批处理和并行计算能力,代表了高性能计算机发展的新方向。在集群或者超级计算机平台上,一般不能随意地直接以 mpiexec 或 mpirun 运行我们的并行计算程序,而必须通过其上提供的作业管理系统来提交计算任务。作为集群系统软件的重要组成部分,集群作业管理系统可以根据用户的需求,统一管理和调度集群的软硬件资源,保证用户作业公平合理地共享集群资源,提高系统利用率和吞吐率。下面我们将简要地介绍几个常用的集群作业管理系统:PBS,LSF 和 SLURM。在下一篇中我们首先简要介绍 PBS 作业管理系统。

你可能感兴趣的:(在 C 语言中嵌入 mpi4py 程序)