目录
MPI的基本概念
MPI(消息传递接口),是一个可以被C、C++和Fortran程序调用的库函数。许多系统可以使用mpicc来编译它,用mpiexec来运行它
MPI_Init函数用来初始化MPI程序,而MPI_Finalize函数标志者MPI程序的结束。一个符合规范的MPI程序,要尽量保证并行程序的代码段始终在这两个函数之间;当然,一个程序中可有多个这样的片段
下面是一个典型的MPI程序的代码格式:
#include "mpi.h" //mpi头文件
int main() {
...
/*MPI初始化,需要说明的是,程序的并行部分应当在此处起始*/
MPI_Init(NULL, NULL);
...
/*MPI代码区退出部分,按照规范,并行代码应当立即结束*/
MPI_Finalize();
...
return 0;
}
通常情况下,我们会用单程序多数据流(SPMD)的方式来编写并行程序,通过不同的进程号分支转移至不同语句,使不同的进程完成不同的功能
进程通信
一个进程发送数据给另一个进程,这样的过程就叫进程通信
通信子是一组进程的集合,该集合之间的进程可以互相发送消息。MPI启动后,由MPI产生的有所进程都可以通信的通信子,称之为MPI_COMM_WORLD
如果想要将数据发送至某个进程,可以调用MPI_Send函数,该函数规指定了发送数据的内容和它的目的地
MPI_Send的行为由MPI的实现来定义,它可以是阻塞也可以是缓冲的,当消息的大小大于系统设置的阈值时,MPI会阻塞该进程;否则MPI会缓冲发送数据,并使函数调用返回
int MPI_Send(
const void* buf, // 发送数据的地址
int count, // 发送数据的大小
MPI_Datatype datatype, // 发送数据的数据类型
int dest, // 目的进程
int tag, // 标记
MPI_Comm comm // 通信子
)
当目标进程想要接收数据时,可以调用MPI_Ricv函数,该函数描述了用于接收数据的缓冲区,以及从何处接收数据;
MPI_Ricv总是阻塞的,除非接收到数据,否则该函数是不会返回的
int MPI_Recv(
void* buf, // 接收数据的地址
int count, // 接收数据的大小
MPI_Datatype datatype, // 接收数据的数据类型
int source, // 源进程号
int tag, // 标记
MPI_Comm comm, // 通信子
MPI_Status *status // 接收数据的状态
)
集合通信
区别于只涉及两个进程之间的通信函数MPI_Send和MPI_Ricv,集合通信是指一个通信中涉及通信子中所有进程的通信方式;为了与集合通信相区别,前者称之为点对点通信
1. 两个常用的集合通信函数MPI_Reduce和MPI_Allreduce。前者将全局操作的结果(如求和)发送至指定进程,而后者将全局操作的结果发送至所有进程
int MPI_Reduce(
void* inpute_data_p // 输入数据的指针
void* output_data_p // 输出数据的指针
int count // 数据的维数
MP