高性能并行计算初步(整理)

更新时间:2023-05-20 19:34:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第一部分:并行程序设计基础

1. 什么是并行计算机:

并行计算机即能在同一时间内执行多条指令或处理多个数据的计算机,并行计算机是并行计算的物理载体。

2. 并行计算机的基本划分:

根据一个并行计算机能够同时执行的指令与处理数据的多少可以把并行计算机分为SIMD (Single-Instruction Multiple-Data )单指令多数据并行计算机和MIMD (Multiple-Instruction Multiple-Data )多指令多数据并行计算机。SIMD计算机同时用相同的指令对不同的数据进行操作;SIMD计算机同时用相同的指令对不同的数据进行操作。

按同时执行的程序和数据的不同又提出了SPMD(Single-Program Multuple-Data )单程序多数据并行计算机和MPMD

(Multiple-ProgramMultiple-Data )多程序多数据并行计算机的概念,这种划分方式依据的执行单位不是指令而是程序。显然其划分粒度要大得多。一般地SPMD并行计算机是由多个地位相同的计算机或处理器组成的,而MPMD并行计算机内计算机或处理器的地位是不同的,根据分工的不同它们擅长完成的工作也不同,因此可以根据需要将不同的程序任务放到MPMD并行计算机上执行。

3.并行计算机的存储方式:

从物理划分上:共享内存和分布式内存是两种基本的并行计算机存储方式,除此之外

分布式共享内存也是一种越来越重要的并行计算机存储方式。

对于共享内存的并行计算机,各个处理单元通过对共享内存的访问来交换信息协调各

处理器对并行任务的处理。

对于分布式内存的并行计算机,各个处理单元都拥有自己独立的局部存储器,由于不存

在公共可用的存储单元,因此各个处理器之间通过消息传递来交换信息协调和控制各个处理器的执行。这是本书介绍的消息传递并行编程模型所面对的并行计算机的存储方式。不难看出通信对分布式内存并行计算机的性能有重要的影响,复杂的消息传递语句的编写成为在这种并行计算机上进行并行程序设计的难点所在,但是对于这种类型的并行计算机由于它有很好的扩展性和很高的性能,因此它的应用非常广泛。

对于分布式共享内存的并行计算机结合了共享内存的并行计算和分布式内存的并行计算机的特点,通过提高一个局部结点内的计算能力,使它成为所谓的超结点,不仅提高了整个系统的计算能力,而且可以提高系统的模块性和扩展性,有利于快速构造超大型的计算系统。

3. 物理问题在并行机上的求解( HOW ? )

物理问题并行求解的最终目的是将该问题映射到并行机上, 忽略并行机的非本质的细节特征可以得到该并行机的并行计算模型,在这一模型上可以设计各种适合该模型的并行算法,这些算法精确描述了该并行模型能够实现的功能,而这些算法是通过用特定的并行语言设计并行程序后得以实现的。

并行程序设计,需要将问题的并行求解算法转化为特定的、适合并行计算模型的并行算

法。首先是问题的并行求解算法必须能够将问题内在的并行特征充分体现出来,否则并行求解算法将无法利用这些并行特征,从而使问题的高效并行求解成为不可能;其次是并行求解模型要和并行计算模型尽量吻合,这样就为问题向并行机上的高效解决提供了前提。

4.最重要的两种并行编程模型:( 数据并行 和 消息传递 ) 数据并行编程模型的编程级别比较高,编程相对简单,但它仅适用于数据并行问题。数据并行即将相同的操作同时作用于不同的数据,因此适合在SIMD及SPMD并行计算机上运行;数据并行编程模型是一种较高层次上的模型,它提供给编程者一个全局的地址空间,一般这种形式的语言本身就提供并行执行的语义,因此对于编程者来说只需要简单地指明执行什么样的并行操作和并行操作的对象,就实现了数据并行的编程。数据并行发展到现在高效的编译实现成为它面临的一个主要问题。

消息传递编程模型的编程级别相对较低,但消息传递编程模型可以有更广泛的应用范围。消息传递即各个并行执行的部分之间通过传递消息来交换信息协调步伐控制执行。为编程者提供了更灵活的控制手段和表达并行的方法,一些用数据并行方法很难表达的并行算法都可以用消息传递模型来实现,灵活性和控制手段的多样化是消息传递并行程序能提供高的执行效率的重要原因。

5.并行语言的产生主要有三种方式:

(1) 设计全新的并行语言;

(2) 扩展原来的串行语言的语法成分使它支持并行特征;即将对串行语言的并行扩充作为原来串行语言的注释,相对于设计全新的并行语言显然难度有所降低,但需要重新开发编译器,使它能够支持扩充的并行部分。

(3) 不改变串行语言仅为串行语言提供可调用的并行库;是一种对原来的串行程序设计改动最小的并行化方法,这样原来的串行编译器也能够使用,不需要任何修改,编程者只需要在原来的串行程序中加入对并行库的调用就可以实现并行程序设计,本书所介绍的MPI并行程序设计就属于这种方式。

6.并行算法的分类:

根据运算的基本对象的不同,可以将并行算法分为数值并行算法(数值计算)和非数值

并行算法(符号计算)

根据进程之间的依赖关系,可以分为同步并行算法(步调一致)、异步并行算法(步调

进展互不相同)和纯并行算法(各部分之间没有关系)

根据并行计算任务的大小,可以分为粗粒度并行算法(一个并行任务包含较长的程序段

和较大的计算量)、细粒度并行算法(一个并行任务包含较短的程序段和较小的计算量)以及介于二者之间的中粒度并行算法。

7.并行算法的设计

对于相同的并行计算模型,可以有多种不同的并行算法来描述和刻画,由于并行算法设

计的不同,可能对程序的执行效率有很大的影响。

于SIMD并行计算机一般适合同步并行算法,而MIMD并行计算机则适合异步并行算

对于机群计算有一个很重要的原则就是:设法加大计算时间相对于通信时间的比重,减

少通信次数甚至以计算换通信。这是因为对于机群系统一次通信的开销要远远大于一次

计算的开销,因此要尽可能降低通信的次数或将两次通信合并为一次通信。机群计算的并行粒度不可能太小,因为这样会大大增加通信的开销,如果能够实现计算和通信的重叠,那将会更大地提高整个程序的执行效率。

对于MPMD并行算法:各并行部分一般是异步执行的,而不是象SPMD那样的同步或松

同步方式,因此只要能够大大降低通信次数,增大计算相对于通信的比重,则该MPMD算法就可以取得较高的效率。

第二部分:基本的MPI并行程序设计

1.什么是 MPI :

MPI是一个库而不是一门语言,许多人认为MPI就是一种并行语言,这是不准确的。但是按照并行语言的分类可以把FORTRAN+MPI或C+MPI 看作是一种在原来串行语言基础之上扩展后得到的并行语言。MPI库可以被FORTRAN77/C/Fortran90/C++调用,从语法上说,它遵守所有对库函数/过程的调用规则,和一般的函数/过程没有什么区别。

MPI是一种标准或规范的代表,而不特指某一个对它的具体实。现迄今为止所有的并行计算机制造商都提供对MPI的支持,可以在网上免费得到MPI在不同并行计算机上的实

现,一个正确的MPI程序可以不加修改地在所有的并行机上运行。

MPI是一种消息传递编程模型,并成为这种编程模型的代表和事实上的标准。MPI虽然很庞大,但是它的最终目的是服务于进程间通信这一目标的。

消息传递方式是广泛应用于多类并行机的一种模式,特别是那些分布存储并行机,尽管在具体的实现上有许多不同, 但通过消息完成进程通信的基本概念是容易理解的。

1993年2月 MPI1.0版本

1995年6月 MPI1.1版本

1997年7月 MPI - 2版本 ( 比MPI – 1版本扩充:并行I/O、远程存储访问、动态进程管理 )

由于MPI是一个库而不是一门语言,因此对MPI的使用必须和特定的语言结合起来进行。FORTRAN是科学与工程计算的领域语言,而C又是目前使用最广泛的系统和应用程序开发的语言之一,因此对FORTRAN和C的支持是必须的!

2.第一个MPI程序(Hello World)的实现:

Fortran 77 + MPI 实现:

program main

include 'mpif.h' ! MPI 相对于 Fortran 实现的头文件

character * (MPI_MAX_PROCESSOR_NAME) processor_name

! MPI_MAX_PROCESSOR_NAME 是MPI 预定义的宏 ,即某一MPI的具体实现中允许机器名字的最大长度,机器名放在变量processor_name中

Integer myid , numprocs , namelen , rc , ierr

! 定义程序中所需要的与 MPI 有关的变量,myid 用来记录某个并行执行的进程的标识,numprocs 用来记录所有参加计算的进程的个数 ,namelen 是实际得到的机器名字的长度 ,rc 用来得到 MPI 过程调用结束后的返回结

果 ,ierr 用来得到 MPI 过程调用结束后可能的出错信息

call MPI_INIT ( ierr )

! MPI 程序的开始必须是 MPI_INIT ,用来完成MPI 程序的初始化工作 call MPI_COMM_RANK ( MPI_COMM_WORLD, myid, ierr )

! MPI_COMM_RANK 得到当前正在运行的进程的标识号,并放在myid中 call MPI_COMM_SIZE ( MPI_COMM_WORLD, numprocs, ierr )

! MPI_COMM_SIZE 得到所有参加运算的进程的个数,并放在numprocs中 call MPI_GET_PROCESSOR_NAME (processor_name, namelen, ierr)

! MPI_GET_PROCESSOR_NAME 得到运行本进程的机器的名称结果,并放在processor_name中,它是一个字符串,而该字符串的长度放在namelen中 write (*,10) myid , numprocs , processor_name

! write语句是普通的FORTRAN语句,它将本进程的标识号、并行执行的进程的个数、运行当前进程的机器的名字输出,和一般的FORTRAN程序不同的是,这些程序体中的执行语句是并行执行的,每一个进程都要执行

10 FORMAT ('Hello World! Process ',I2,' of ',I1,' on ', 20A)

Call MPI_FINALIZE (rc)

! MPI 程序的结束必须是 MPI_FINALIZE ,用来完成 MPI 程序的结束工作 end

不妨指定本程序启动时共产生4个进程同时运行,而运行本程序的机器的机器名为“tp5 4”,个进程都在tp5上运行,其标识分别为0、

1、 2、 3, 执行结果如图所示,虽然这一 MPI 程序本身只有一条输出语句,但是由于它启动了四个进程同时执行,每个进程都执行打印操作,故而最终的执行结果有四条输出语句如下:

Hello World ! Process 0 of 4 on tp5

Hello World ! Process 1 of 4 on tp5

Hello World ! Process 2 of 4 on tp5

Hello World ! Process 3 of 4 on tp5

Fortran 90 + MPI 实现:

Program main

use mpi

character * (MPI_MAX_PROCESSOR_NAME) processor_name

integer myid, numprocs, namelen, rc, ierr

call MPI_INIT ( ierr )

call MPI_COMM_RANK ( MPI_COMM_WORLD, myid , ierr )

call MPI_COMM_SIZE ( MPI_COMM_WORLD, numprocs , ierr )

call MPI_GET_PROCESSOR_NAME (processor_name , namelen , ierr)

print * , "Hello World! Process " , myid , " of " , numprocs, " on " , processor_name call MPI_FINALIZE (rc)

end

本文来源:https://www.bwwdw.com/article/1f44.html

Top