# MPI 简介
MPI (Message Passing Interface) 是一个消息传递接口。目前超算中心一般选择 OpenMPI 及其衍生实现或 MVAPICH 及其衍生实现(太湖之光使用 MVAPICH 衍生)。因为 MPICH 不支持一些比较新式的硬件。以下内容将主要讨论 OpenMPI。

在编译 OpenMPI 时,需要首先搞清楚服务器的硬件架构以及环境配置书写对应的编译指令。


OpenMPI 的主要架构分为三层,OMPI 提供编程接口;ORTE 用于起进程;OPAL 和操作系统进行交互。每一层只能向下动态引用。
# MPI 编程
# 编程理念
SPMD (Single Program, Multiple Data)。同一个程序会被拷贝多份,对应的代码指令是相同的,处理的数据是不一样的。
一个简单的例子:



# 点对点(Point-to-Point)




# 案例分析:乒乓通信
#include <stdio.h> | |
#include <mpi.h> | |
#include <stdlib.h> | |
int main(int argc, char* argv[]) | |
{ | |
MPI_Init(&argc, argv); | |
int numP, myId; | |
MPI_Comm_size(MPI_COMM_WORLD, &numP); | |
MPI_Comm_rank(MPI_COMM_WORLD, &myId); | |
if (numP % 2 != 0) | |
{ | |
if (!myId) | |
{ | |
// only process 0 put the error message | |
printf("ERROR: the number of ping pong processes must be an even number\n"); | |
MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); | |
} | |
} | |
int parter_id; | |
int odd = myId & 1; // Is myId even or odd? | |
if (odd) | |
{ | |
// If myId is odd: | |
partner_id = myId - 1; | |
} | |
else | |
{ | |
// If myId is even: | |
partner_id = myId + 1; | |
} | |
int a, b; | |
if (odd == 0) | |
{ | |
// If myId is even, first send then receive: | |
a = -1; | |
printf("Process %d sends token %d to process %d\n", myId, a, partner_id); | |
MPI_Send(&a, 1, MPI_INT, partner_id, 0, MPI_COMM_WORLD); | |
MPI_Recv(&b, 1, MPI_INT, partner_id, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | |
printf("Process %d receives token %d from process %d\n", myId, b, partner_id); | |
} | |
else | |
{ | |
// If myId is odd, first receive then send: | |
a = 1; | |
MPI_Recv(&b, 1, MPI_INT, partner_id, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | |
printf("Process %d receives token %d from process %d\n", myId, b, partner_id); | |
printf("Process %d sends token %d to process %d\n", myId, a, partner_id); | |
MPI_Send(&a, 1, MPI_INT, partner_id, 0, MPI_COMM_WORLD); | |
} | |
MPI_Finalize(); | |
} |

如果将 send 打印语句放在 MPI_Send
后面,会出现乱序的结果(程序设定是偶数进程先发送再接受,奇数进程先接受再发送),但是结果消息中进程 2 在进程 3 发送前就接受到了,这是不符合函数执行顺序的。
