MPI多线程并行计算工具mpi4py
1. MPI
MPI的全称是Message Passing Interface,即消息传递接口。
- 它并不是一门语言,而是一个库,我们可以用Fortran、C、C++结合MPI提供的接口来将串行的程序进行并行化处理,也可以认为Fortran+MPI或者C+MPI是一种再原来串行语言的基础上扩展出来的并行语言。
- 它是一种标准而不是特定的实现,具体的可以有很多不同的实现,例如MPICH、OpenMPI等。
- 它是一种消息传递编程模型,顾名思义,它就是专门服务于进程间通信的。
MPI的工作方式很好理解,我们可以同时启动一组进程,在同一个通信域中不同的进程都有不同的编号,程序员可以利用MPI提供的接口来给不同编号的进程分配不同的任务和帮助进程相互交流最终完成同一个任务。就好比包工头给工人们编上了工号然后指定一个方案来给不同编号的工人分配任务并让工人相互沟通完成任务。
2. 基本MPI函数
mpi4py是一个构建在MPI之上的Python库,主要使用Cython编写。mpi4py使得Python的数据结构可以方便的在多进程中传递。
mpi4py是一个很强大的库,它实现了很多MPI标准中的接口,包括点对点通信,组内集合通信、非阻塞通信、重复非阻塞通信、组间通信等,基本上我能想到用到的MPI接口mpi4py中都有相应的实现。不仅是Python对象,mpi4py对numpy也有很好的支持并且传递效率很高。同时它还提供了SWIG和F2PY的接口能够让我们将自己的Fortran或者C/C++程序在封装成Python后仍然能够使用mpi4py的对象和接口来进行并行处理。可见mpi4py的作者的功力的确是非常了得。
2.1 工具
a. 通信子(通信空间)
MPI_COMM_WORLD
在MPI中的作用:
- 一个通信空间是一个进程组和一个上下文的组合.上下文可看作为组的超级标签,用于区分不同的通信子.
- 在执行函数MPI_Init之后,一个MPI程序的所有进程形成一个缺省的组,这个组的通信子即被写作MPI_COMM_WORLD.
- 该参数是MPI通信操作函数中必不可少的参数,用于限定参加通信的进程的范围.
from mpi4py import MPI
MPI.COMM_SELF
# <mpi4py.MPI.Intracomm at 0x7f2fa2fd59d0>
MPI.COMM_WORLD
# <mpi4py.MPI.Intracomm at 0x7f2fa2fd59f0>
b. 获取进程
转到python中的mpi4py
from mpi4py import MPI
# 用Get_size 获得进程个数 p
size = MPI.COMM_WORLD.Get_size()
# Get_rank 获得进程的一个叫rank的值,
# 该rank值为0到p-1间的整数,相当于进程的ID号
rank = MPI.COMM_WORLD.Get_rank()
c++中的定义类似
int MPI_Comm_size(MPI_Comm comm, int *size)
int MPI_Comm_rank(MPI_Comm comm, int *rank)
3. 通信
因为mpi4py中点对点的 通信send语句,在数据量较小的时候是把发送数据拷贝到缓存区,是非堵塞的操作, 然而在数据量较大时候是堵塞操作。
阻塞操作见 python的MPI多线程并行通信方式
3.1 点对点通信
所谓点对点通信,即单个线程与单个线程之间通信。
(a) 两个线程之间点对点通信。
# test.py
from mpi4py import MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
if rank == 0:
data = {
'a': 7, 'b': 3.14}
comm.send(data, dest=1, tag=11)
data['a'] = 8; data['b'] = data['b'] *