MPI 编程实战:从 Hello 到并行归约
摘要:上一篇只打印,这一篇真正并行算。以"全集群求和"为例子,从点对点通信(Send/Recv)演进到集合通信(MPI_Reduce),给出完整可编译代码、运行方式与结果验证。
1. 场景:把"求和"并行化
需求:N 个进程各自持有数值 ,计算全集群总和。
- 串行:一个人累加
- 并行:各进程算自己的 → 汇总到 0 号进程
2. 版本一:点对点(MPI_Send / MPI_Recv)
c
#include <mpi.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
MPI_Init(NULL, NULL);
int size, rank;
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int value = rank + 1; // 每个进程自己的数
int sum = 0;
if (rank == 0) {
sum = value; // 0 号先收自己
for (int i = 1; i < size; i++) {
int recv;
MPI_Recv(&recv, 1, MPI_INT, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
sum += recv;
}
printf("Total sum = %d\n", sum);
} else {
MPI_Send(&value, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}bash
mpicc -o mpi_sum mpi_sum.c
mpirun -np 8 ./mpi_sum
# Total sum = 36 (1+2+...+8)特点:逻辑直观,但通信是串行的(0 号进程逐个收)。进程一多,0 号会成为瓶颈。
3. 版本二:集合通信(MPI_Reduce)
c
#include <mpi.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
MPI_Init(NULL, NULL);
int size, rank;
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int value = rank + 1;
int sum = 0;
// 所有进程的值按 SUM 操作归约到 0 号进程
MPI_Reduce(&value, &sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
if (rank == 0)
printf("Total sum (Reduce) = %d\n", sum);
MPI_Finalize();
return 0;
}bash
mpicc -o mpi_sum2 mpi_sum2.c
mpirun -np 8 ./mpi_sum2
# Total sum (Reduce) = 36一行
MPI_Reduce替代全部 Send/Recv,底层用树形聚合,扩展性远好于点对点版本。这就是为什么真实 HPC 应用几乎全用集合通信。
4. 集合通信速查
| 函数 | 作用 | 常用场景 |
|---|---|---|
MPI_Bcast | 广播:根进程发给所有人 | 分发参数/矩阵 |
MPI_Reduce | 归约:所有人 → 根进程聚合 | 求和、求最大值、全局误差 |
MPI_Allreduce | 归约并广播给所有人 | 每个进程都要最终结果 |
MPI_Scatter | 分发给各进程一部分 | 数据分块 |
MPI_Gather | 各进程数据收到根进程 | 收集结果 |
MPI_Barrier | 同步屏障 | 阶段对齐 |
5. 运行注意
5.1 进程数与节点
bash
# 8 个进程:4 节点 × 每节点 2 进程
mpirun -perhost 2 -machinefile hostfile -np 8 ./mpi_sum25.2 多节点 fabric(与 hello world 一致)
bash
# 以太网
mpirun -perhost 2 -np 8 -genv I_MPI_FABRICS shm:ofi -genv FI_PROVIDER tcp -machinefile hostfile ./mpi_sum2
# InfiniBand
mpirun -perhost 2 -np 8 -genv I_MPI_FABRICS shm:ofi -genv FI_PROVIDER mlx -machinefile hostfile ./mpi_sum25.3 结果验证
- 串行校验:,与程序输出对照。
- 换
-np跑多次,确认结果一致——这是 MPI 正确性的第一关。
6. 从求和到真实负载
这套模式稍加扩展就是真实应用:
- 求全局误差/范数:
MPI_Allreduce(MPI_SUM)收集各进程局部误差 - 并行矩阵运算:
MPI_Scatter分块 + 局部计算 +MPI_Gather收结果(HPL 的雏形) - 数值模拟:每进程算自己的网格,
MPI_Sendrecv交换边界
7. 小结
- 点对点(Send/Recv)适合少量、定向通信;集合通信(Reduce/Bcast 等)适合大规模。
- 并行程序验证三步走:小规模跑通 → 换进程数结果一致 → 与串行结果对照。
至此,"CPU 理论计算 → 性能预估 → HPL 实测 → MPI 环境 → Hello → 编程"已构成完整的 CPU 实战链路。相关指南:CPU HPL 测试指南 (Intel)。