mpi4py 仅提供标准 MPI 功能的包装器。 OMPI_COMM_TYPE_SOCKET 是 Open MPI 特定的拆分类型。如果您知道它的数值,您仍然可以在 mpi4py 中使用它,因为它只是 C enum 的成员:
/*
* Communicator split type constants.
* Do not change the order of these without also modifying mpif.h.in
* (see also mpif-common.h.fin).
*/
enum {
MPI_COMM_TYPE_SHARED,
OMPI_COMM_TYPE_HWTHREAD,
OMPI_COMM_TYPE_CORE,
OMPI_COMM_TYPE_L1CACHE,
OMPI_COMM_TYPE_L2CACHE,
OMPI_COMM_TYPE_L3CACHE,
OMPI_COMM_TYPE_SOCKET, // here
OMPI_COMM_TYPE_NUMA,
OMPI_COMM_TYPE_BOARD,
OMPI_COMM_TYPE_HOST,
OMPI_COMM_TYPE_CU,
OMPI_COMM_TYPE_CLUSTER
};
#define OMPI_COMM_TYPE_NODE MPI_COMM_TYPE_SHARED
成为enum 的成员意味着OMPI_COMM_TYPE_SOCKET 的实际数值取决于它在enum 中的位置,因此可能因Open MPI 的一个版本与另一个版本不同。您有多种选择。
硬编码值
这是最简单的选择。打开mpi.h(ompi_info --path incdir 为您提供它的位置),计算OMPI_COMM_TYPE_SOCKET 在封闭enum 中的位置,从0 开始为MPI_COMM_TYPE_SHARED 并硬编码该值。代码可能会因与您不同的 Open MPI 版本而中断。
解析mpi.h
阅读mpi.h,搜索enum 定义并找到包含OMPI_COMM_TYPE_SOCKET 的定义。假设MPI_COMM_TYPE_SHARED 是0,则OMPI_COMM_TYPE_SOCKET 的值是它在枚举值序列中从0 开始的索引。这在很大程度上取决于 mpi.h 中的代码是否具有特定格式,并且如果发生更改很容易中断。
解析mpif.h
Fortran 接口更容易解析,因为它的值定义为:
parameter (OMPI_COMM_TYPE_SOCKET=6)
这很容易用一个简单的正则表达式解析。问题是 Open MPI 的最新版本将 mpif.h 拆分为几个文件,然后将这些文件包含在 mpif.h 中,当前值在 mpif-constants.h 中。因此,您可能需要解析 include 语句并递归到它们引用的文件中。请注意,这些是 Fortran include 语句,而不是预处理器 #include 指令。
代码生成
编写一个小型 C 程序,将 OMPI_COMM_TYPE_SOCKET 的值输出到 Python 文件,并将其作为程序设置过程的一部分运行。比如:
#include <stdio.h>
#include <mpi.h>
int main (int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: mkompimod /path/to/module.py\n");
return 1;
}
FILE *fh = fopen(argv[1], "w");
if (fh != NULL) {
fprintf(fh, "COMM_TYPE_SOCKET = %d\n", OMPI_COMM_TYPE_SOCKET);
fclose(fh);
}
return 0;
}
将其放入名为mkompimod.c 的文件中。使用mpicc -o mkompimod mkompimod.c 编译并使用mkompimod /path/to/ompi.py 运行以创建一个Python 文件ompi.py,其值为OMPI_COMM_TYPE_SOCKET。导入它并在对comm.Split_type()的调用中使用它:
import ompi
socketcomm = comm.Split_type(ompi.COMM_TYPE_SOCKET)
用 C 编写 Python 模块
这有点复杂,但您可以编写一个包含mpi.h 的C 模块,并将OMPI_COMM_TYPE_SOCKET 的值导出为Python 常量。请咨询Python documentation,了解如何用 C 编写扩展。
使用 CFFI 模块
CFFI 允许您构建包装 C 库的 Python 模块并为您编写所有胶水代码。将以下内容放入名为 ompi_build.py 的文件中:
from cffi import FFI
ffi = FFI()
ffi.set_source("ompi", r"#include <mpi.h>")
ffi.cdef(
r"""
const int OMPI_COMM_TYPE_HWTHREAD;
... more constants here ...
const int OMPI_COMM_TYPE_SOCKET;
... even more constants here ...
"""
)
if __name__ == "__main__":
ffi.compile(verbose=True)
像这样运行:
$ CC=mpicc python ompi_build.py
这将创建 C 模块 ompi.c 并将其编译为可加载的 DSO。然后你可以像这样导入它并访问常量:
from ompi.lib import OMPI_COMM_TYPE_SOCKET
socketcomm = comm.Split_type(OMPI_COMM_TYPE_SOCKET)
CFFI 提供与 Python 的 distutils 的集成,您可以让它在设置过程中自动构建 C 模块。
使用 Cython
mpi4py 本身就是这样编写的。它将 C 和 Python 混合成一个单一的神秘语法。阅读源代码。试着弄清楚发生了什么以及如何自己写一些东西。帮不了你。
无论您选择哪种方式,请记住,所有这些都与程序将在其上运行的系统有关,而不仅仅是程序将在其上开发的系统。