并行计算与 MPI
【链接地址】https://blog.csdn.net/tomjchan
1. 并行计算
1.1. 相关背景
(1)从 1986 年到 2002 年,微处理器的性能以平均 50%的速度不断提升。但从 2002 年
开始,单处理器的性能提升速度下降到每年大约 20%,这个差距是巨大的。所以,从 2005
年起,大部分主流的 CPU 制造商决定通过并行处理来快速提升微处理器的性能。
(2)单处理器性能大幅度提升的主要原因之一是日益增加的集成电路晶体管密度。随
着晶体管尺寸减小,传递速度增快,集成电路整体的速度也加快,它们的能耗也相应增加,
而在 21 世纪的前 10 年中,用空气冷却的集成电路的散热能力已经达到极限了,所以,集成
电脑制造商的决策是:与其构建更快、更复杂的单处理器,不如在芯片上放置多个相对简单
的处理器,这样的有多个处理器的集成电脑称之为多核处理器。
(3)通常我们传统单核处理器上编写的程序无法利用多核处理器,我们需要使得程序
充分利用处理器更快的运行程序,更加及时与逼真的模拟现实世界。为了达到这一目的,需
要软件开发工程师将串行程序改写为并行程序。
1.2. 什么是并行计算
并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程,是提
高计算机系统计算速度和处理能力的一种有效手段。它的基本思想是用多个处理器来协同求
解同一问题,即将被求解的问题分解成若干个部分,各部分均由一个独立的处理机来并行计
算。并行计算系统既可以是专门设计的、含有多个处理器的超级计算机,也可以是以某种方
式互连的若干台的独立计算机构成的集群。通过并行计算集群完成数据的处理,再将处理的
结果返回给用户。
并行计算或称平行计算是相对于串行计算来说的。所谓并行计算可分为时间上的并行和
空间上的并行。时间上的并行就是指流水线技术,而空间上的并行则是指用多个处理器并发
的执行计算。
并行计算科学中主要研究的是空间上的并行问题。从程序和算法设计人员的角度来看,
并行计算又可分为数据并行和任务并行。空间上的并行导致了两类并行机的产生,按照 Flynn
(弗林)分类法为:单指令流多数据流(SIMD)和多指令流多数据流(MIMD)。我们常用的
串行机也叫做单指令流单数据流(SISD)。
图 1 弗林分类法划分的四类计算机
MIMD 类的机器又可分为以下常见的五类:并行向量处理机(PVP)、对称多处理机(SMP)、
大规模并行处理机(MPP)、工作站机群(COW)、分布式共享存储处理机(DSM)。
1.3. 主要目的
并行计算(parallel computing)是在并行机上,将一个应用分解成多个子任务,分配给
不同的处理器,各个处理器之间相互协同,并行地执行子任务,实现如下两个主要目的:
(1)加速求解问题的速度。
(2)提高求解问题的规模。
1.4. 并行计算与分布式计算
并行计算不同于分布式计算(distributedcomputing)。分布式计算主要是指,通过网络相
互连接的两个以上的处理机相互协调,各自执行相互依赖的不同应用,从而达到协调资源访
问,提高资源使用效率的目的。但是,它无法达到并行计算所倡导的提高求解同一个应用的
速度,或者提高求解同一个应用的问题规模的目的。对于一些复杂应用系统,分布式计算和
并行计算通常相互配合,既要通过分布式计算协调不同应用之间的关系,又要通过并行计算
提高求解单个应用的能力。
1.5. 并行的基本条件
并行计算是在并行机上,将一个应用分解成多个子任务,分配给不同的处理器,各个处
理器之间相互协同,并行地执行子任务,从而达到加速求解速度,或者求解应用问题规模的
目的。由此,为了成功开展并行计算,必须具备三个基本条件:
(1)并行机。并行机至少包含两台或两台以上处理机,这些处理机通过互连网络相互
连接,相互通信。
(2)应用问题必须具有并行度。也就是说,应用可以分解为多个子任务,这些子任务
可以并行地执行。将一个应用分解为多个子任务的过程,称为并行算法的设计。
(3)并行编程。在并行机提供的并行编程环境上,具体实现并行算法,编制并行程序,
并运行该程序,从而达到并行求解应用问题的目的。
1.6. 主要的并行系统
1.6.1.共享内存模型
共享内存系统即单机并行,在一台机器上运行程序时分配多个进程或线程来达到加速的
目的。比如用 OpenMP 和 Pthreads 进行共享内存编程,在程序中加入相关并行语句实现线
程的创建和销毁。
OpenMP 是由 OpenMP Architecture Review Board 牵头提出的,并已被广泛接受的,用于
共享内存并行系统的多线程程序设计的一套指导性的编译处理方案(Compiler Directive)。
OpenMP 支持的编程语言包括 C 语言、C++和 Fortran;而支持 OpenMp 的编译器包括 Sun
Compiler,GNU Compiler 和 Intel Compiler 等。OpenMp 提供了对并行算法的高层的抽象描
述,程序员通过在源代码中加入专用的#pragma 来指明自己的意图,由此编译器可以自动将
程序进行并行化,并在必要之处加入同步互斥以及通信。当选择忽略这些#pragma,或者编
译器不支持 OpenMP 时,程序又可退化为通常的程序(一般为串行),代码仍然可以正常运
作,只是不能利用多线程来加速程序执行。
每台电脑的核数,是一个程序中同时运行的最大线程数或进程数(这里的同时指同一时
刻,注意区分并行和并发的概念)。例如用 OpenMP 进行编程,一般情况下如果设置的线程
数大于电脑核数是毫无意义的,因为同时运行的线程数只能等于核数,此时多余的线程变为
并发运行,这样在线程切换上会浪费更多的时间。
共享内存模型具有如下特性:
(1)在共享编程模型中,任务间共享统一的可以异步读写的地址空间。
(2)共享内存的访问控制机制可能使用锁或信号量。
(3)这个模型的优点是对于程序员来说数据没有身份的区分,不需要特别清楚任务简
单数据通信,程序开发也相应的得以简化。
(4)在性能上有个很突出的缺点是很难理解和管理数据的本地性问题。
1.6.2.消息传递模型
消息传递模型有以下特征:
(1)计算时任务集可以用他们自己的内存。多任务可以在相同的物理处理器上,同时
可以访问任意数量的处理器。
(2)任务之间通过接收和发送消息来进行数据通信。
(3)数据传输通常需要每个处理器协调操作来完成。例如,发送操作有一个接受操作
来配合。
1.6.3.数据并行模型
数据并行模型有以下特性:
(1) 并行工作主要是操纵数据集。数据集一般都是像数组一样典型的通用的数据结构。
(2)任务集都使用相同的数据结构,但是,每个任务都有自己的数据。
(3)每个任务的工作都是相同的,例如,给每个数组元素加 4。
(4)在共享内存体系结构上,所有的任务都是在全局存储空间中访问数据。在分布式
存储体系结构上数据都是从任务的本地存储空间中分离出来的。
1.6.4.对比分析
在当前并行机上,比较流行的并行编程环境的典型代表、可移植性、并行粒度、并行操
作方式、数据存储模式、数据分配方式、学习难度、可扩展性等方面的比较在下表中给出。
表 1 两种并行编程环境主要特征一览表
典型代
并行粒
并行操
数据存
数据分
学习入
可扩
特征
可移植性
表
度
作方式
储模式
配方式
门难度
展性
消息
MPI、
所有流行
进程级
传递
PVM
并行机
大粒度
OpenMP SMP﹑DSM
线程级
细粒度
异步
异步
分布式
存储
共享存
储
显式
较难
好
隐式
容易
较差
共享
存储
数据
并行
SMP﹑DSM
进程级
松散同
共享存
HPF
半隐式 偏易
一般
﹑MPP
细粒度
步
储
由该表可以看出:
(1)共享存储并行编程基于线程级细粒度并行,仅被 SMP 和 DSM 并行机所支持,可
移植性不如消息传递并行编程。但是,由于它们支持数据的共享存储,所以并行编程的难度
较小,但一般情形下,当处理机个数较多时,其并行性能明显不如消息传递编程。
(2)消息传递并行编程基于大粒度的进程级并行,具有最好的可移植性,几乎被当前
流行的各类并行机所支持,且具有很好的可扩展性。但是,消息传递并行编程只能支持进程
间的分布存储模式,即各个进程只能直接访问其局部内存空间,而对其他进程的局部内存空
间的访问只能通过消息传递来实现。因此,学习和使用消息传递并行编程的难度均大于共享
存储和数据并行两种编程模式。
2. MPI
2.1. 什么是 MPI
多线程是一种便捷的模型,当中每一个线程都能够訪问其他线程的存储空间。因此,这
样的模型仅仅能在共享存储系统之间移植。一般来讲,并行机不一定在各处理器之间共享存
储,当面向非共享存储系统开发并行程序时,程序的各部分之间通过来回传递消息的方式通
信。要使得消息传递方式可移植,就须要采用标准的消息传递库。这就促成的消息传递接口
(Message Passing Interface, MPI)的面世,MPI 是一种被广泛采用的消息传递标准。
MPI 是一种基于消息传递的跨语言的并行编程技术,支持点对点通信和广播通信。消息
传递接口是一种编程接口标准,而不是一种详细的编程语言。简而言之,MPI 标准定义了一
组具有可移植性的编程接口。各个厂商或组织遵循这些标准实现自己的 MPI 软件包(如链
接库等形式),典型的实现包含开放源码的 MPICH、LAM MPI 以及不开放源码的 Intel MPI。
因为 MPI 提供了统一的编程接口,程序员仅仅须要设计好并行算法,使用对应的 MPI 库就
能够实现基于消息传递的并行计算。MPI 支持多种操作系统,包含大多数的类 UNIX 和
Windows 系统。
MPI 概念的要点如下:
(1)MPI 是指 Message Passing Interface,消息传递接口,是一个由专家、工业界和学
术界组成的大型的委员会定义的一套标准;
(2)MPI 1.0 版于 1994 年推出,并同时获得了各并行机产商的具体实现;MPI 2.0 版
于 1998 年 10 月推出;
(3)MPI 是一种消息传递编程模型,MPI 的实现为并行应用提供消息传递或者相关的
服务,并且成为了消息传递编程模型的代表和事实上的标准;
(4)MPI 是一种标准或者规范,目前存在对多种 MPI 标准的实现;
(5)MPI 标准定义了一组接口函数,使应用程序可以将消息从一个 MPI 进程送到另一
个 MPI 进程。 MPI 实际上定义了比消息传递更多的服务,但是其核心和灵魂还是 MPI 进程
间的消息传递。
2.2. MPI 的实现
MPI 是一个标准。它不属于任何一个厂商,不依赖于某个操作系统,也不是一种并行编
程语言。不同的厂商和组织遵循着这个标准推出各自的实现,而不同的实现也会有其不同的
特点。
两个值得注意的 MPI 实现是开源的 LAM/MPI(来自 Indiana 大学)和 MPICH(来自
Argonne 国家实验室)。这两个 MPI 实现都有完整的 MPI-1 支持和部分支持 MPI-2。这两个实
现都可以在网上自由获得,并可以用于很多并行和集群环境。MPICH 是影响最大、用户最多
的 MPI 实现。眼下可下载的最新的 MPICH 软件包为 MPICH1.2.7pl 和 2008 年 2 月 15 日公布
的 MPICH 2-1.0.7 测试版,在 http://www.mcs.anl.gov/research/projects/mpich2/index.php 能
够下载到,分别有支持 UNIX 和 Windows 的 32 位和 64 位的版本。
2.3. MPI 基本函数
MPI 程序是基于消息传递的并行程序。消息传递指的是并行运行的各个进程具有自己独
立的堆栈和代码段,作为互不相关的多个程序独立运行,进程之间的信息交互全然通过调用
通信函数来完成。
MPI 调用接口的总数虽然庞大,但根据实际编写 MPI 的经验,常用的 MPI 调用的个数
却有限。用户只需学习 MPI 库函数的标准接口,设计 MPI 并行程序,便可在支持 MPI 并行
编程环境的具体并行机上执行该程序。
下面是 7 个最基本的 MPI 函数。
表 3 MPI 常用接口函数
函数名
函数功能
MPI_Init(…);
并行环境初始化
MPI_Comm_size(…);
获得进程个数 size
MPI_Comm_rank(…); 得到本进程在通信空间中的 rank 值,即在组中的逻辑编号
MPI_Send(…);
发送数据
MPI_Bcast(…);
广播发送数据
MPI_Recv(…);
接收数据
MPI_Finalize();
退出 MPI 系统, 表明并行代码的结束,结束除主进程外其它进程