在上一篇中我們介紹了用 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 <mpi.h>
#include <Python.h>
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 <mpi.h>
#include <Python.h>
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 文檔。