---
title: 高性能计算之MPI——集合通信漫谈-官方技术文章-鲲鹏社区
description: MPI集合通信漫谈
keywords: MPI,高性能计算之,集合通信漫谈,官方技术文章,鲲鹏社区,的暴雷,集合通信,先从广播开始
url: https://www.hikunpeng.com/developer/techArticles/20250922-2?envFlag=1
section: (其他)
---

# 高性能计算之MPI——集合通信漫谈-官方技术文章-鲲鹏社区

URL: https://www.hikunpeng.com/developer/techArticles/20250922-2?envFlag=1
描述: MPI集合通信漫谈
关键词: MPI,高性能计算之,集合通信漫谈,官方技术文章,鲲鹏社区,的暴雷,集合通信,先从广播开始

官方技术文章 [了解详情](https://www.hikunpeng.com/zh/developer/techArticles)

高性能计算之MPI——集合通信漫谈

高性能计算之MPI——集合通信漫谈

HPC

发表于 2025/09/22

0

去年8、9月份，我写了一篇关于MPI的介绍文章《高性能计算之MPI--10分钟超越99%的程序员》。

该文章收到较多反馈与催更，因此抽空更新MPI系列第二篇帖子。

## P2P的暴雷：集合通信

在上一期MPI介绍的时候，提到了Send（）和Recv（接收）。Send/Recv有个专门的名字：P2P。这里的P2P可不是前些年在金融界暴雷的P2P借贷，虽然它们来源于同一个英文单词：Peer-To-Peer。Peer-To-Peer，翻译成中文就是"点对点"。这很容易理解，因为Send和Recv本身就是从一个进程把数据给另外一个进程，即从一个点到另外一个点。上一期中我们假设了这样一个场景：进程0如果要把数据给其他三个进程：进程1、进程2和进程3。这种情况就不单单是一个进程和另外一个进程之间的互操作了，而是一系列进程之间的互操作。这种有别于P2P的、涉及到多个进程之间的通信叫做：集合通信（Collective Communication）.

## 集合通信：先从广播开始

对于上述情况，如果使用P2P的Send/Recv来表达，大概长下面这个样子。/* File Name: mpi_naive_bast.cthe MPI bast example (naive vesion) */#include <stdio.h>#include <stdlib.h>#include <mpi.h>int main(int argc, char **argv) {MPI_Init(NULL, NULL);/* tag */int tag = 10086;int count = 1;MPI_Status status;int rank;MPI_Comm_rank(MPI_COMM_WORLD, &rank);if (rank == 0) {int *sendbuff = (int *)malloc(sizeof(int) * count);sendbuff[0] = 100;/* rank0 -> rank 1/2/3: sendbuff */for (int recvrank = 1; recvrank < 4; recvrank++) {MPI_Send(sendbuff, count, MPI_INT, recvrank, tag, MPI_COMM_WORLD);}}if (rank != 0) {int *recvbuff = (int *)malloc(sizeof(int) * count);/* rank 1/2/3 receive buffer from rank 0 */MPI_Recv(recvbuff, 1, MPI_INT, 0, tag, MPI_COMM_WORLD, &status);printf("I'm rank #%d, recvbuf[0] = %d \n", rank, recvbuff[0]);}MPI_Finalize();return 0;}

最终打印的结果是：`I'm rank #1, recvbuf[0] = 100``I'm rank #3, recvbuf[0] = 100``I'm rank #2, recvbuf[0] = 100`虽然达到了最终的目的，但这种naive的写法简直是老太婆的裹脚布——又臭又长。事实上，MPI标准中提供了一个非常完美的集合通信接口来表示上述的操作，这个操作叫做Broadcast（广播）`int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm)`这些入参中buffer、count、datatype、comm的概念我们前面都提及过，重点说说这里的root的含义。上述例子中，是进程0发给了所有进程，所以root=0. 如果是进程1发给其他进程，则root=1. 以此类推。所以，Bcast中的root进程就是发起广播通信的进程。话不多说，直接上代码吧。/* File Name: mpi_bcast.cthe MPI Bcast example */#include <stdio.h>#include <stdlib.h>#include <mpi.h>int main(int argc, char **argv) {MPI_Init(NULL, NULL);int count = 1;MPI_Status status;int rank;

MPI_Comm_rank(MPI_COMM_WORLD, &rank);int *buf = (int *)malloc(sizeof(int) * count);if (rank == 0) {buf[0] = 100;}/* Before Broadcast, only rank 0 has buffer value: 100 */printf("I'm rank #%d, Before Bcast: buffer value: %d\n", rank, buf[0]);MPI_Bcast(buf, count, MPI_INT, 0, MPI_COMM_WORLD);/* After Broadcast, all ranks has buffer value: 100 */printf("I'm rank #%d, After Bcast: buffer value: %d\n", rank, buf[0]);MPI_Finalize();return 0;}

打印结果如下：`I'm rank #2, Before Bcast: buffer value: 439634824``I'm rank #3, Before Bcast: buffer value: 1004776328``I'm rank #0, Before Bcast: buffer value: 100``I'm rank #1, Before Bcast: buffer value: 752221064`

`I'm rank #0, After Bcast: buffer value: 100``I'm rank #2, After Bcast: buffer value: 100``I'm rank #1, After Bcast: buffer value: 100``I'm rank #3, After Bcast: buffer value: 100`可以看到：在调用Bcast之前，除了进程0之外，其他进程都是随机数。经过Bcast之后，所有数字统一变成了100.使用MPI_Bcast语义最显著的好处是：代码行数由原来的34行缩短到了24行，代码行数降低了29.4%，意味着开发效率直接提升29.4%。不好意思，看到数字就想算个百分数，职业病犯了属于是。显然，集合通信接口的诞生不仅是为了提升代码简洁度，而是为了提升代码效率。或者更确切地说法是：将把优化工作由MPI的使用者抛给了计算机科学家。至于为啥要这么做，我在本文的最后一章里会重点说明。先回到代码效率提升这个问题，其实只要稍加分析，就明白：用Send/Recv描述出来的Bcast是个相当低效。因为进程0在给进程1、2、3的同时，啥也没做。为了更好地量化这个过程，假设一次发和收的时间为t在上面过程中，我们完成了：`Step 1: rank 0 -> rank 1``Step 2: rank 0 -> rank 2``Step 3: rank 0 -> rank 3`三次的发包和收包的过程，所以耗时一共是3t既然大家和接受的信息是一样的，那么在进程1接受到进程0发的信息时，能不能用作发包呢？听上去这个主意不错，上面这个过程就改造成了：`Step 1: rank 0 -> rank 1``Step 2: rank 0 -> rank 2``Step 3: rank 1 -> rank 3`虽说还是三步走，但刚才那个已经是"老三步", 现在我们要走的是"新三步"."新三步"和"老三步"最大的不同是：Step2 和 Step3是可以并行执行的！也就是说，rank 0->rank 2, rank 1->rank 3是可以同时进行的。这样一来：Bcast总的耗时由原来3t的变成了2t时间缩短1/3，性能提升1/3啊。不好意思，看到数字就想算个百分数的职业又犯了。其实，无论是上述的"老三步"还是"新三步"，都是MPI_Bcast的算法。"老三步"的术语名称叫做：Flat-Tree，翻译成中文：平坦的树。

Flat Tree算法示意图，图片来源参考文献[1].刚才的例子中只有4个进程，有很多Tree算法都可以实现上面说的"新三步"的逻辑，比如：Binary Tree、K-Chain Tree等等。具体参考文献[1].文字太麻烦，不如直接上图：

不同Tree算法示意图，图片来源参考文献[1].

## 性能分析与测试基准

前面一章，提到了Bcast和实现Bcast的不同算法。这里面天然地引入两个问题：1、如何评估一个Bcast算法的好坏？2、如何实测一个Bcast算法的好坏？对于第一个问题，评价通信的具体模型很多，这里不做展开。评价通信时间开销，最核心的是这样一个公式。

其中，T表示通信总时间，α表示通信时延（Latency)，L表示通信量，β表示带宽（Bandwidth）。这个公式是评价通信时间开销/通信复杂度最重要的公式，其地位与算法复杂度分析的大O模型相当。这个公式表明，当通信量不大时（即L比较小时），时延是影响通信总耗时的关键因素；当通信量很大时（即L比较大时），带宽是影响通信总耗时的关键因素。对于第二个问题，业界有很多测评MPI性能的Benchmark和测试集(Test Suite)，参考文献[2].使用最多的是OSU Benchmark，官网参考：https://mvapich.cse.ohio-state.edu/benchmarks/ [了解详情](https://mvapich.cse.ohio-state.edu/benchmarks/)冷知识：OSU是Ohio State University（俄亥俄州立大学）的简称。这是因为OSU benchmark是一位来自俄亥俄州立大学的教授Dhabaleswar Panda（熊猫教授）提出的。使用次多的是IMB，是Intel MPI Benchmark的简称：https://www.intel.com/content/www/us/en/developer/articles/technical/intel-mpi-benchmarks.html [了解详情](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-mpi-benchmarks.html)从名字上不难发现，这是Intel公司提出的一套测试集。

## 集合通信の分类

除了Bcast外，还有那些集合通信语义呢？有很多，比如Scatter、Gather、Allgather

从上图中可以看出：Scatter的含义是：进程0原来有一段数据，要把数据Scatter到其他进程。Gather的含义则恰好相反——所有的进程把数据汇总到进程0中。所以Gather和Scatter是互为逆操作。观察一下，MPI_Allgather的操作可以看做是：Gather+Bcast. 即：

再比如，Reduce和Allreduce.

Reduce（规约）操作：就是把所有进程的求和（SUM）、乘积（Prod）、最大值（Max）或最小值（Min）从各个进程求解出来，最终结果放在进程0.上图例子，进程0/1/2/3在Reduce前分别拥有的数字是5、2、7、4，在进过Reduce操作后，这四个数字的之和18就会放在进程0中。可以看到，Allreduce相比Reduce规约操作，不同点在于：Reduce的结果只会放在进程0中，而allreduce的结果则会放在所有进程中。也就是说：这些集合通信可以大概分为三类：· One-To-Many（一对多）· Many-To-One（多对一）· Many-To-Many（多对多）其实分类的名字还挺形象的：如果集合通信前，原数据掌握在一个进程，集合通信结束后，需要的数据被所有进程都有，那就是One-To-Many。比如本篇重点介绍的Bcast，又比如刚才提到的Scatter和Reduce.相反地，如果在集合通信前，数据在多个进程中； 而在集合通信结束后，需要的数据被唯一一个进程所拥有，那就是Many-To-One. 比如刚才介绍的Gather操作。如果集合通信前后，数据都在所有进程中，那就是Many-To-Many，比如Allreduce、Allgather和Alltoall.这里有个规律：凡是API接口属于"All字辈"，基本都是Many-To-Many类型。

## 一名HPC从业者的碎碎念

观前提示：如果你看这篇文章的目的只是单纯地想学习和了解MPI，那么这一章就可以跳过了。如果你想听一个在HPC领域摸爬滚打了几年的人碎碎念，顺带给你讲讲私货，那么欢迎来到本章节。前面章节在提到MPI集合通信接口的诞生原因时，我说了这么一句话：MPI集合通信接口的诞生本质上是把优化工作由MPI的使用者抛给了计算机科学家。这句话背后的逻辑是：使用MPI的人和优化MPI的人是两拨人。真可谓“遍身罗绮者，不是养蚕人”。前面的文章中我提到过，HPC这个领域最重要的是上层各式各样的应用。这些应用通常是为了解决某一个或某一类科学问题，比如气象（天气预报）、物理学（高能物理、核物理）、医疗制药（分子结构模拟）、机械制造（计算流体力学）等等。HPC应用通常都是谁写的呢？显然，都是一些科学家，或者科研工作者。如果按照专业划分的话，这些人来自于大气科学系、物理系、化学系、机械系等等，可谓"百花齐放、百家争鸣"。MPI（进程级并行）是这些HPC应用最常见的并行策略和并行方式；这些五花八门的人就是MPI的最大用户群体。HPC程序开发完成后，对一个有追求的开发者而言。他的第一个问题是：如何能让我的程序跑得快一点？程序的性能优化是HPC应用开发者们不太擅长的，还是得学计算机的人来。计算机专家做优化，往往需要理解应用里面的逻辑，可应用的逻辑往往不太好懂。这里举个例子：计算物理学中有个重要的分支：计算电磁学（Computational Electromagnetics）.计算电磁学的核心是求解麦克斯韦方程组。这个方程长这样：咱们就先不说能不能理解方程的实质，单单要想弄懂上面那个倒着写的三角符的含义，最起码得学过微积分+矢量代数。这还不算完。这些微分方程要变成可求解的方式需要一系列的算法。在计算电磁领域，常用算法包括但限于：有限差分法、有限元方法、矩量法、快速多极子方法。把这些算法理解完成后，才能把程序的架构设计出来，才具备写程序的现决条件。我有位从事HPC应用优化且计算机科班出身的同事告诉我：他们去HPC相关的学术会议听报告，最怕听到应用的人讲报告，全是满屏的公式，连符号都看不懂。每次到了这些环节，都昏昏欲睡。说了半天，我想表达的核心观点是：对从事性能优化的计算机专家来说，HPC应用的算法逻辑太复杂了。这句话并非贬低学计算机的人。其实即使对同是物理专业的人，做计算电磁的和做流体力学仿真的两个子领域的人都不能相互理解。这都不是“隔行如隔山”，这属于“隔小行如隔山，隔行如隔大山”。说回MPI，MPI集合通信接口的设计把MPI的使用者（HPC应用开发者）和MPI优化者（计算机科学家）划了一条清晰的分割线：对HPC应用开发者来说，他们可以轻松地使用这些接口，把这些优化工作交给更专业的计算机专家来做。MPI是个把两拨人分开的很好的例子，但悲剧的是：在高性能计算领域，这样的例子并不算多。在本系列的第一篇文章中，我就表达过一个观点：HPC这个领域，容易学起来上瘾。HPC这个领域还是太复杂了，需要懂的东西太多了。知识一多，就容易学杂。学杂了，一不小心把书架上的《母猪的产后护理》给抽出来了。不抖机灵，送给大家一句话：学无止境。与诸君共勉。感谢阅读。这个专栏有没有下一期，就看各位的点赞、收藏和关注了。你还想知道点儿啥，评论区告诉我。

（本文原载于知乎，知乎作者也是本人，原文链接： [了解详情](https://zhuanlan.zhihu.com/p/715049734)https://zhuanlan.zhihu.com/p/1899504956299534916 [了解详情](https://zhuanlan.zhihu.com/p/1899504956299534916)）

参考文献[1]. EminNuriyev et al, Model-based selection of optimal MPI broadcast algorithms for multi-core clusters, Journal of Parallel and Distributed Computing. 2022.[2]. Sascha Hunold and Alexandra Carpen-Amarie, MPI Benchmarking Revisited: Experimental Design and Reproducibility.https://arxiv.org/pdf/1505.07734 [了解详情](https://arxiv.org/pdf/1505.07734)[3]. Jan Thorbecke, Programming with MPI Collectives,https://janth.home.xs4all.nl/MPIcourse/PDF/05_MPI_Collectives.pdf [了解详情](https://janth.home.xs4all.nl/MPIcourse/PDF/05_MPI_Collectives.pdf)[4]. MPI Tutorial: MPI Bcast and Collective Communication:https://mpitutorial.com/tutorials/mpi-broadcast-and-collective-communication/ [了解详情](https://mpitutorial.com/tutorials/mpi-broadcast-and-collective-communication/) [了解详情](https://mpitutorial.com/tutoria)

本页内容
