并行计算-准备篇
Posted 寒潭
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并行计算-准备篇相关的知识,希望对你有一定的参考价值。
1、背景知识
从1986年到2002年,微处理器的性能以平均50%的速度不断提升。但是,从2002年开始,单处理器的性能提升速度降到每年大约20%,这个差距是巨大的:如果以每年50%的速度提升,在10年里,微处理器的性能能提升60倍,而如果以20%的速度提升的话,10时间里,只能提升6倍。所以,从2005年起,大部分主流的CPU制造商决定通过并行处理来快速提升微处理器的性能。他们不再继续开发速度更快的单处理器芯片,而是开始将多个完整的单处理器放到一个集成电路芯片上。这一变化对软件人员带来了重大的影响,也由此引出了一系列的问题:
为什么需要不断提升的性能?
过去的几十年,借助不断提升的计算能力,人类在许多领域(如:人类基因解码、医疗成像、人工智能、虚拟现实等)发展的非常迅速。但随着人类在科学步伐的前进,这里领域的许多应用在计算能力上的要求也越来越高,解决问题的规模也在不断的增加。
图1 气象模拟 图2 蛋白质分析 图3 药物发现
为什么需要构建并行系统?
单处理器性能大幅度提升的主要原因之一是日益增加的集成电路晶体管密度。随着晶体管尺寸减小,传递速度增快,集成电路整体的速度也加快,它们的能耗也相应增加。大多数能量是以热能的形式消耗,而在21世纪的前10年中,用空气冷却的集成电路的散热能力已经达到极限了,所以,集成电脑制造商的决策是:与其构建更快、更复杂的单处理器,不如在芯片上放置多个相对简单的处理器,这样的有多个处理器的集成电脑称之为多核处理器。
为什么需要编写并行程序?
通常我们传统单核处理器上编写的程序无法利用多核处理器,我们需要使得程序充分利用处理器更快的运行程序,更加及时与逼真的模拟现实世界。为了达到这一目的,就需要软件开发工程师将串行程序改写为并行程序。
怎么样编写并行程序?
广泛采用的两种方式:任务并行和数据并行。
任务并行:是指将有待解决的问题需要执行的任务分配到各个核上完成。
数据并行:是指将有待解决的问题所需要处理的数据分配到各个核上完成,每个核在所分配的大致相当的数据集上执行相同操作。
这里我们举个例子来说明什么是任务并行,什么是数据并行?假如一个学校的高三总共有200个学生,有5个数学老师,分别是A、B、C、D、E老师,到期末考试的时候,数学试卷出了5道题目进行考试,在阅卷的时候,有两种方案:每个人负责一道题目进行打分;或者将学生分成5组,每人负责一组,即20个学生。在这两种方案中,数学老师充当计算机核的角色。
在第一种方案中,可以认为是任务并行的例子。有五个任务(题目)需要执行,即给批阅第一道题、批阅第二道题、……批阅第五道题。每个人执行的指令是不相同的。应该每一道题的内容不同。
而第二种方案中,可以认为数据并行的例子,“数据”就是学生的试卷,在不同的核(打分人)之间平分,每个核执行大致相同的指令。
2、并行硬件
我们目前的计算机都是基于经典的冯偌伊曼结构的:主存+CPU+总线(互连设备)。根据Flynn(费林)分类法,即基于指令和数据流方式,可以将并行计算机划分为:SISD、MISD、SIMD和MIMD四种。具体如下图:
图4 硬件系统
通俗的讲,SISD系统即是我们典型的冯诺依曼系统,它是一次执行一条指令,一次存取一个数据项。而其它三个才是真正的并行计算系统。SIMD系统通过对多个数据执行相同的指令,从而实现在多个数据流上的操作,因此,该系统非常适合处理大型数组的简单循环,从此衍生出向量处理器,重点对数组或数据向量进行操作。这里重点说明一下,我们常说的GPU(graphics processing unit)图形处理器计算机就是讲物体表面的内部表示为使用点、线、面的像素数组来表示的,也是一个概念上的SIMD系统,不过随着技术的发展,现代的GPU也可以有几十个核,每个核也能独立的执行指令流。
在并行计算中,一般将MIMD作为主要研究对象。其中MIMD系统主要有两种类型:共享内存系统(图5)和分布式内存系统(图6)。
图5 共享内存系统 图6 分布式内存系统
在共享内存系统中,自治的CPU通过互连网络与内存系统相连,每个CPU都能访问每个内存系统中的内存。分布式内存系统中,每个CPU都有自己的独立内存,每个单元之间的内存访问通过消息通讯或者特殊的函数来进行。
3、并行软件
SPMD(单程序多数据流):指的不是在每个核上运行不同的程序,而是一个程序仅包含一份代码,通过一定的条件分支,使得这一份代码再执行的时候表现的像是在不同的处理器上执行不同的代码。
在我们主要讨论的MIMD分布式内存系统中,各个核能够直接访问自己的内存,而运行在不同核之间的进程需要交换内存数据的时候,只能通过消息传递API来实现。消息传递的API至少要提供一个发送函数和接收函数。进程之间通过它们的序号(rank)进行识别。
我们编写并行计算程序的主要目的当然是为了提供它们的性能,那么我们应该如何去评价一个并行计算程序的性能呢?答案是:加速比与效率。
加速比:
效率:
理论上而言,如果使用p个进程或者线程来运行一个并行程序,并且每个核中之多只有一个进程/线程,那么,S=p,E=1。但是在实际情况下,S<p,E<1。既然已经知道如何评价一个将串行程序改为并行程序的性能,那么现在假设我们已经有了一个串行程序,为了提高性能,我们如何将串行程序改为高性能的并行计算程序呢?需要哪些步骤?
一般情况下,需要将工作进行拆分,使得分布在每个进程中的工作量大致相仿,并行让它们之间的通信量最少。于是串行程序并行化设计步骤一般按以下几步进行:
第一步:划分。将串行程序中需要要执行的指令和数据按照计算部分拆分成多个小任务。关键:识别出可以进行并行执行的任务。
第二步:通讯。确定第一步识别出来的任务之间需要执行那些通信。
第三步:凝聚/聚合。将第一步确定的任务与通信结合成更大的任务。
第四步:分配。将上一步聚合好的任务分配到进程/线程中。这一步还主要注意的是,要使得通信量最小化,让各个进程/线程所得到的工作量大致均衡。
4、实现的手段
4.1 MPI
MPI实现并行是进程级;采用的是分布式内存系统,显式(数据分配方式)实现并行执行,通过通信在进程之间进行消息传递,可扩展性好。MPI虽适合于各种机器,但它的编程模型复杂:
- 需要分析及划分应用程序问题,并将问题映射到分布式进程集合;
- 需要解决通信延迟大和负载不平衡两个主要问题;
- 调试MPI程序麻烦;
- MPI程序可靠性差,一个进程出问题,整个程序将错误;
4.2 Pthreads
Pthreads实现并行是线程级;采用的是共享内存系统,只有在POSIX的系统(linux、mac OS X、Solaris、HPUX等)上才有效。它是一个可以连接到C程序中的库,目前标准的C++共享内存线程库还在开发中,也许在将来在C++程序中,使用这个库更加方便。
4.3 OpenMP
OpenMP是线程级(并行粒度);采用的是共享内存系统,隐式(数据分配方式)实现并行执行;可扩展性差;正因为采用共享内存分布系统,意味着它只适应于SMP(Symmetric Multi-Processing 对称多处理结构),DSM(Distributed Shared Memory 共享内存分布系统)机器,不适合于集群。
4.4 OpenCL
全称Open Computing Language,开放运算语言。是一个为异构平台编写程序的框架,此异构平台可由CPU,GPU或其他类型的处理器组成。OpenCL由一门用于编写kernels (在OpenCL设备上运行的函数)的语言(基于C99)和一组用于定义并控制平台的API组成。OpenCL提供了基于任务分割和数据分割的并行计算机制。OpenCL类似于另外两个开放的工业标准OpenGL和OpenAL,这两个标准分别用于三维图形和计算机音频方面。
4.5 GPU
GPU是专门为执行复杂的数学和集合计算而设计的,一个GPU内有许多流处理簇(stream Multiprocessor)SM,他们就类似于CPU的核。这些SM与共享(一级缓存)连接在一起,然后又与相当于SM间互联开关的二级缓存相连。类似于这种设计,都是为计算图形渲染所必须的。
4.6 Hadoop
是谷歌公司MapReduce框架的一个开源版本。它针对的是linux平台。其概念是你取来一个大数据集,然后将其切割或映射(map)成很多小的数据块。然而,并不是将数据发送到各个节点,取而代之的是数据集通过并行文件系统已经被划分给上百或者上千个节点。因此,归约(Reduce)步骤就是把程序发送到已经包含数据的节点上,然后输出结果写入本地节点并保存在那里。
以上是关于并行计算-准备篇的主要内容,如果未能解决你的问题,请参考以下文章