并行计算讲义.docx
- 文档编号:30490374
- 上传时间:2023-08-15
- 格式:DOCX
- 页数:89
- 大小:200.98KB
并行计算讲义.docx
《并行计算讲义.docx》由会员分享,可在线阅读,更多相关《并行计算讲义.docx(89页珍藏版)》请在冰豆网上搜索。
并行计算讲义
Lastrevisionon21December2020
并行计算讲义
燕山大学课程讲义
并行计算导论
授课人:
郭栋梁
学时:
32学时
其中实验课:
8学时三级项目:
16学时
第1章引言
概述
单处理器计算机即将成为过时的概念.我们需要考虑如下因素来着手改进提高计算机
的性能:
(1)单纯依靠单处理器很难提升现有计算机的性能.即使有一个性能十分强大的单处理器,其功耗也让人无法接受.想要提升计算机的性能,更加可行的方法是同时使用多个简单处理器,它所能达到的性能可能是现有单处理器计算机性能的几千倍。
(2)观察结果显示,除非使用并行处理技术,一个程序在一台型号更新的单处理器计算机上的运行速度,可能比在旧的计算机上的运行速度更慢。
能依照给定算法检测出程序中的并行结构的编程工具还有待开发。
此算法需要能够检测出变ja之间的依赖关系是否规则;而且不管这些依赖是否规则,此算法都能在保证程序正确性的前提下,通过将程序中的一些子任务并行化来加速程序的执行。
(3)提升未来的计算机性能的关键就在于并行程序的开发,这涉及各个层面的工作:
算法、程序开发、操作系统、编译器及硬件设备。
(4)并行计算除了要考虑到参与并行计算的处理器的数量,还应该考虑处理器与处理器、处理器与内存之间的通信。
最终计算性能的提升既依赖于算法能够提升的空间,更依赖于处理器执行算法的效率。
而通信性能的提升则依赖于处理器对数据的供应和提取的速度。
(5)内存系统的速度始终比处理器慢,而且由于一次只能进行单个字的读写操作,内存系统的带宽也有限制。
(6)内存系统的速度始终比处理器慢,而且由于一次只能进行单个字的读写操作,内存系统的带宽也有限制。
本书内容主要涉及并行算法与为了实现这些算法而设计的硬件结构。
硬件和软件是相互影响的,任何软件的最终运行环境是由处理器组成的底层硬件设备和相应的操作系统组成.我们在本章开始的部分会介绍一些概念,之后再来讨论为了实现这些概念有哪些方法和限制.
自动并行编程
对于算法在软件中的实现过程我们都很熟悉。
在编程并不需要了解目标计算机系统的具体细节,因为编译器会处理这些细节.但是在编程和调试时依旧沿用着在单一央处理器(CPU)上顺序处理的模式.从另一方面讲,为了实现并行算法,硬件和软件之间的相互联系需要比我们想象的更加密切。
图展示了基于软件和硬件、利用并行计算机来运行程序的主要步骤和层次。
从最顶层开始,第5层是指应用层,在这一层里描述的是需要并行计算平台实现的应用和问题。
对应所需的输入和输出的格式也在这层进行定义。
某些输人和输出((I/O)接口的描述还需要考虑数据存储的位置和时间相关性。
这一层的结果会被更低一层采纳以便指导并行算法的开发工作。
第4层是算法开发层,这里需要考虑到应用在问题中的实现。
需要应用实现的计算内容决定了算法的具体任务和任务之间的相互依赖关系(interdependence)。
在这一阶段,算法的并行性并不一定会显现出来,因为在探索算法子任务执行的时候仍然在运用传统的线性思考。
在这一阶段,也不需要考虑子任务的时间调度和处理器分配的问题。
可能在现阶段就将这些问题解决的做法看起来很诱人,但是这样做会适得其反,因为这会掩盖程序中潜在的并行性。
该层的结果是一个依赖图,或是一个有向图,或者是一个概括了任务之间依赖关系的临界矩阵。
第3层是并行化层,在这一层将试着释放算法中潜在的并行性。
这一层接收了第4层对算法的描述并且给出了基于软件实现的线程时间调度和处理器分配。
另一种选择是在这一层进行基于超大规模集成电路的硬件实现的任务调度和处理器分配。
本书内容主要集中在这一层上,在图用灰色方形显示。
第2层是代码层,在本层中并行算法用高级语言表示为代码。
使用何种语言取决于目标并行计算在何种平台执行。
图1.1中右侧的分支表示算法在通用并行计算平台上的实现过程。
这一做法即是我们所说的“并行编程”。
并行计算机程序由所谓的“并发平台”执行,此种平台帮助编程人员管理线程,处理处理器级别的任务执行时间调度。
并发平台包括Cilk++,OpenMP,CUDA(computeunifieddevicearchitecture统一计算设备架构)。
图1.1中左侧的分支表示并行算法在定制的硬件设备上的实现,例如脉动阵列计算机。
编程人员使用硬件描述语言(HDL),例如Verilog,或者超高速集成电路硬件描述语言(VHDL)。
第1层的目标是算法的实现,或是在并行计算机平台的应用.实现的途径可以是在并行计算平台上使用多线程,也可以是在特定用途集成电路(ASIC)上或者现场可编程门阵列(FPGA)上使用特定的应用并行处理系统.
那么并行计算机自动编程又是什么意思呢现在我们已经可以进行线性计算机自动编程.程序员用像C,Java,FORTRAN这样的高级语言编写代码,这些代码可以被计算机自动编译,不需要程序员再去做进一步的工作。
更重要的是,程序员编程的时候也不需要了解底层计算平台的硬件细节.甚至在程序员完全不需要知道内存结构,也不知道CPU的信息和产他细节的情况下,代码就可以迅速地转化为结果。
上述的一切能用在并行编程上吗我们需要的并行编译器要能找到简单环路和解决处理器的分配等问题.而且这种编译器还能轻松地解决现在被称为“让人尴尬的并行算法”(译注:
也就是相对独立的可以完全并行执行的算法)的问题[2.3]。
除此之外,程序员还需要对处理器之间的行为有着充分的了解,并且知道算法需要在何时执行。
自动并行编程
IEEE电子工程名词标准词典里对于“算法”一词的定义如下:
为了描述在有限步骤内解决某一个问题而定义的过程或者规则。
一个算法的任务或者过程一般是独立的。
有些任务可以并发执行,但有些必须线性地按顺序进行.根据上述的定义,任何算法都是由并行和非并行两部分组成的。
除了某些极端的情况,很难定义某些算法是并行的而某些是完全串行的(即非并行),后面将探讨如何量化一个算法的并行度。
如果某个算法由W个子任务组成,则称与这个算法有关的操作数是W.定义一个算法的基本组成部分如下:
(1)不同的子任务。
(2)子任务之间的依赖关系。
当某一个子任务的输入是另一个子任务的输出时,他们之间则存在依赖关系。
(3)算法的初始输入集。
(4)算法的最终输出集。
我们通常用有向图(以下简称DG)来直观地表示算法的子任务之间的数据依赖关系。
DG在描述算法的时候表示依赖图,需要用带箭头的线段强调子任务之间的数据流向关系.换句话说,如果一个依赖图的边没有箭头表示方向,就很难从图中得知数据的依赖关系。
定义一个依赖图是边和结点的集合.结点表示算法的子任务,边表示子任务用到的数据.数据包括输人、输出和中间结果.
需要注意的是,在一个依赖图中出现的不带箭头的边表示此边连接的两个结点之间没有数据依赖关系,它们只是共用算法中的某一个变量。
这个变量可以是输入、输出或者在算法中作为I\O媒介的中间结果。
定义DG是有向边和结点的集合。
结点表示算法需要处理的子任务,有向边表示子任务之间的数据依赖关系.一个子任务的输出在一条边的开端部分,箭头指向的一端表示一个子任务的输入。
定义有向无环图(DAG)址指一个没有任何环路的DG.
图是一个示例算法的DAG,根据源结点和目标结点的关系来加以分类,在一个DAG或者DG里有3种不通过的边。
定义一个DG中的输人边是指只有目标结点而没有任何源结点的边,表述了算法的一个输入。
在图中,可以粉到有3条这样的输人边,分别表示了输人in0,in1,和in2
定义一个DG中的内部边是指既有源结点又有目标结点的边,表述了算法的一个内部变量。
定义一个DG中的输入结点是指所有的人边都是输入边的结点。
在图1.2中,可以看到结点0,1和2都表示输人结点。
输人结点所表示的子任务在算法输人变量就绪后就被处理。
定义一个DG中的输出结点是指所有的出边都是输出边的结点。
图中,可以看到结点7和9都表示输人结点。
但结点3不是输出结点,因为结点3的一条出边是指向结点7的内部边。
定义一个DG中的内部结点是有至少一条人边和至少一条出边的结点。
算法的邻接矩阵
一个算法也可以用一个邻接矩阵A来表示。
若算法中有W个子任务,就有一个W×W阶的0-1矩阵来表示这个算法,其中a(i,j)=1表示结点i的输人依赖于结点j的输出,j是源结点而i是目标结点。
当a(i,j)=0表示结点i的输入不依赖于节点j的输出。
对于任何0<=i 上述定义的邻接矩阵是非对称的,因为当a(i,j)=1和a(j,i)=1同时生时就会构成一个环路。 例如,图的邻接矩阵A如下。 矩阵A有一些很有趣的性质值得研究.若在i行每一个元素都等于0,则结点i是一个输入结点;若j列上都等于0,则结点j是一个输出结点.可以用等式表示为: 此外其他结点都是内部结点。 在矩阵A中,第0,1和2行的元素都是0,表示结点0、结点1和结点2都是输人结点,这三行的元素都用黑体显示。 第7列和第9列的元素都是0,表明结点7和结点9都是输出结点,这两列的元素也都用黑体显示。 其他行和列中都有超过1个非零元素,表明这些结点都是内部结点。 若结点i有元素a(i,j)=1则说结点J是结点i的母结点。 依据子任务的依赖关系可以大致将算法分为如下几类: (1)串行算法。 (2)并行算法。 (3)串行一并行算法(SPA). (4)非串行一并行算法(NSPA) (5)正则迭代算法(RIA) 最后一类算法可以看做SPA的泛化。 值得一提的是,根据数据或者任务的粒度的不同,算法的分类也随之改变。 例如说,如果矩阵的元素相加是一项基本操作,求两个矩阵的和就可以看做是一个串行算法。 若另一台计算机上的基本操作是相关行列的相加,那我们的算法就变成了基于行列的并行算法。 另一项值得一提的事情是,一些算法的子任务可能会有不同类型的算法。 依旧可以用矩阵相加的运算来说明。 在并行计算机中两组相关行的计算可以同时在两个不同的处理器上执行。 但在每个处理器上相关行上的元素又是串行处理的,因此这个并行算法中就包含了行相加的串行算法。 稍后我们会详细讨论这些分类。 串行算法的特点是由于相互之间存在数据依赖关系,子任务必须一个一个地按顺序执行。 这一类算法的DG是由一系列关联的子任务构成的队列图1.3(a)展示了一个串行算法的DG。 此类算法是用来计算斐波那契数列的。 为了得到n10,子任务T10进行了如下计算: n10=n8+n9 在此n0=1和n1=1初始条件已经给出.很明显,为了得到某一位的斐波那契数只能依次计算在它之前的数。 并行算法的特点是由于相互之间不存在数据依赖关系,子任务可以同时并发执行。 此类算法的DG就像是许多独立的子任务组成的一组任务,相互之间没有联系。 图1.3(b)展示了一个并行算法的DG,Web服务器上的数据处理应用就是一种简单的并行算法,每一次数据请求都被看做独立的任务交给不同的处理器来响应.同时运行浏览器,字处理程序等多个程序时操作系统的多任务调度算法也是一种并行算法。 SPA SPA的特点是子任务被分配推不同层次,每个层次之内的子任务可以并发执行,但是各个层次需按照一定的顺序执行.当需要执行的层次只有一层时,这个SPA就是并行算法。 当每一层都只有一个子任务时.这个SPA是串行算法。 图1.3(c)展示了CORDIC算的DG,CORDIC算法就是一个典型的SPA它有n层迭代,在第i次迭代时需要执行以下运算: 在此等式中x,y和z都是进行迭代的数据.每次迭代之后都会被更新。 和 是存在表单中的常量.m是用来控制计算类型的参数, 的数值是预设的.与i有关.此算法每次迭代都会进行这三项操作,这里并不研究该算法的细节。 NSPA NSPA不属于上述分类中的任何一种,NSPA算法的DG也没有规律可循。 根据算法DG是否有环我们将NSPA分为两大类: (1)DAG。 (2)有向有环图(DCG), 图(a)展示了一个DAG算法,图(b)是一个DCG算法.DCG算法常见于离散时间回谈控制系统。 输入信号作为子任务T0的初始滤波或者愉人信号条件.子任务T1的输出通常是错误信号,然后这个信号会作为一种反馈输入子任务T2中。 NSPA的依赖图有两种典型构造: 结点用来表示构成算法的子任务,有向边则表示子任务之间的数据流向.一个结点的一条出线表示输出,入线表示的是输入。 若Ti的输出指向Tj,我们则说Tj依赖于Ti.在图中我们则用“结点i的一条有向边指向结点j”来表示这种依赖关系。 一个算法的DG有如下3个重要属性: (1)Work任务数(W)表示算法完成需要处理的子任务总数。 (2)Depth深度(d)表示任f“个输人结点到任意一个输出结点之间的最大路径长度,也被称为关键路径。 (3)Parallelism并行度(P),也被称为并行程度,表示可以并发执行的最结点数.由此数据可以决定这个算法需要的处理器的数目不会超过P,这样一来在算法执行过程中就不会出现不必要的空闲处理器. 第8章会对这些性质进行进一步探讨上实现。 此外还会研究如何将这样的算法在并行。 RIA Karp等介绍了RIA的概念.此类算法需要特别加以说明,因为此类算法涵盖范围甚广,包括信号处理、图像和视频处理,线性代数应用。 以及基于网格结构的数字模拟程序,图是一个RIA的依赖图,用作示例的是图像匹配算法。 对干RIA算法我们不绘制DAG来表示.而是用依赖图的概念来表示. 依赖图和DAG类似.但是依赖图中的连接边是无向边.依赖图的具体画法在第9章,第10章以及第11章会详细叙述. RIA中的任务依赖关系图十分复杂。 串行算法和并行算法,甚至SPA算法的并行度计算都不复杂。 但是RIA算法的并行度计算十分困难。 矩阵乘算法就是简单的RIA算法,具体见算法 算法中出现的变量和算法的因子i,j,k有着正则依赖关系。 一般情况下此类算法通过依赖图来进行研究,依赖图能展示需要执行的子任务之间的关系。 当算法只有1个或2个因子时,依赖图是很直观的。 但是矩阵相乘算法出现了3个因子,因此它的依赖图是三维的,很难直观表示。 并行算法实现 上一节讨论了根据子任务之间的依赖关系不同,我们将算法分为几个不同的类别,本节将探讨根据算法的类型如何将算法在并行计算机上利用软件或硬件实现。 这涉及算法的并行化.根据算法的类型不同采取相应并行化的策略。 设计并行计算系统 本节讨论的是在设计并行计算系统时需要注意的一些重要问题.并行计算系统的设计需要考虑许多方面。 设计者需要选择一个能处理预期任务的基础处理器架构。 处理器应该是一个简单的单元,也可以是一个能运行多线程操作系统的超标量处理器。 处理器之间的通信应采用内部互联网络.此网络应该有能力支持任意两个处理器之间的即时通信。 处理器之间的连接方式类似于电信中的信道。 数据交换的方式需要详细的说明。 总线互联是最简单的内部互联网的实现方式.数据的交换基本单位是字。 系统有一个时钟负责通知处理器数据是否可用。 如今总线已经被网络芯片(NoC)代替.数据在网络芯片上交换的基本单位是数据包,使用路由器来计算数据之间的传输线路. 数据和程序需要储存在特定的内存系统中,设计者可以选择让处理器共享内存模块.或者可以为每一个处理器都分配特定的内存模块。 若采用共享内存的设计,系统需为读和写操作分配不同的内存模块。 读和写的顺序需保证数据完整性.若某个数据被某个处理器更改过,其他处理器应被告知此更改以确保数据的正确性. 任务或者程序在一个并行计算机上的实现需要考虑如下问题.任务分割表示将原始程序或应用分为几个程序段,以便稍后将它们分配至各个处理器上.粗粒度分割是指分配至各个处理器的程序段体积较大.细粒度分割则是指程序段的体积较小。 程序段可以是不同的软件进程或者是线程.由程序员或者编译器决定分割方式.程序员或者操作系统必须要确保子任务的同步执行以保证程序的正确性和数据的完整性. 并行算法和并行体系结构 并行算法和并行体系结构是紧密结合在一起的。 在思考并行算法的时候必须要考虑到支撑这个算法的并行硬件系统。 同时,在设计一个并行硬件系统的时候也不能不考虑在其上运行的并行算法.并行计算在一个计算机系统上的实现的层次是不同的,可以通过硬件实现、也可以由软件来实现。 数据级并行是指同时对数据的多个位或者多个数据进行运算,例如位并行加法和二进制除法,向量处理器阵列以及处理多份数据样本的脉动阵列都属于数据级并行。 数据级并行是本书的主题。 (1)指令级并行(ILP)是指处理器同时执行多条指令,例如指令流水线的应用。 (2)线程级并行(TLP)。 线程是程序的一部分,线程之间共享处理器资源。 有些时候线程也被称为轻量级进程。 TLP是指由一个或者多个处理器同时执行某个软件的多个线程. (3)进程级并行。 进程就是指计算机正在执行的程序。 一个进程会占有特定的计算机资源,例如专用的内存空间和寄存器。 通常意义的进程级并行就是指多任务处理或者分时计算系统,即在一台或者多台计算机上同时运行几个程序。 并行算法和并行体系结构相关概念 IEEE电子工程名词标准词典里将软件的“并行”定义为: “分别使用独立的设备,并且在同一时刻转移、产生或者处理构成一个整体的几个独立部分,例如构成一个字符的每一位,或者构成一个字的每一个字符。 ”在此定义之下,若一个算法的某些步骤可以分别由不同的硬件同时处理,我们就可以说此算法是并行的。 定义并行算法的时候已经默认了存在支持并行算法运行的硬件环境,这同时表明软件的并行化与执行这个软件代码的硬件是密不可分的。 软件的并行通过使用不同的线程或者进程来实现,而并行基于硬件的实现则是通过使用不同的处理器。 当代码中出现FOR或者WHILE这类的关键词的时候,能很快得出此算法可以并行的结论。 IEEE电子工程名词标准词典里对于“并行体系结构”的定义如下: ”可以执行并行处理的多处理器结构”。 为多个处理器分配任务以保证系统高效率工作是程序员和编译器以及操作系统的职责。 在如下领域中我们可以找到许多并行算法的实例: ·科学计算领域中的物理仿真,微积分公式求解,风洞测试模拟。 ·计算机图形学领域中的图像处理,视频压缩,以及光线跟踪。 ·医学成像领域中的核磁共振成像(MRI)以及计算机断层x线扫描术(CT). 在很多领域,特别是在信息技术领域中,包括在线医疗数据检索、网上银行业务、数据挖掘、数据仓库以及数据库检索系统中并行算法并没有得到充分应用。 通过开发来提升IT应用的计算机体系结构和软件是当前面临的诸多挑战之一。 算法的实现: 两个方面问题 图展示了本书将探讨的一些问题,左侧表示算法空间,右侧表示执行算法的并行体系结构空间.路径A表示的情况如下: 已知一个具体算法,要满足预期的性能并考虑系统的限制,需要为实现此算法寻求合理的硬件结构或者处理器阵列。 此时的问题简而言之就是为给定的并行算法寻求可行的并行硬件体系结构。 路径B表示如下一种常见的情况: 并行体系结构或者多核系统是已知的,要解决的问题是在满足预期的性能并考虑系统限制的条件下,为并行算法的实现寻求最优解。 简而言之就是在一个给定的体系结构中研究如何将并行算法的任务合理地分配至处理器端。 这需要程序员、编译器与操作系统一起来解决此问题,它涉及多线程并行编程技术。 不论是选择路径A还是B都需要解决以下问题: (1)将子任务映射至不同的处理器。 (2)遵循算法的数据依赖关系和数据的I/O要求,合理调度子任务的执行顺序。 (3)识别I/O接口和处理器之间的数据交换。 衡量并行计算的优势 本节回顾一下之前的一些重要结论,列举使用并行计算带来的好处。 但首先要讨论一些用于定量分析的重要指标。 衡量一个并行计算是否优秀的一个重要标准是对比某个任务在单处理器和N个并行多处理器上的执行时间。 N个并行处理器的加速比S(N)可以定义为: 其中Tp (1)表示单处理器系统运行算法的时间,Tp(N)表示多处理器系统运行算法的时间.理想条件下,忽略处理器和内存之前的通信时间,在一个完全并行化的算法中Tp(N)=Tp (1)/N,则上述等式变为: 但在现实情况中很难得到这样的结果,原因会在以后的章节中说明. 无论是并行系统还是单处理器系统,计算数据的读取和写人都是不可避免的步骤.内存的通信开梢是由于处理器和内存之间的信息交换速度的不对称。 此外,在并行系统中 处理卷之间也有大显数据交换,例如在内部网络中的信息交换和数据的转移.” 处理器之间的通信主要有如下几点困难需要克服: (1)内部网络延迟: 通过内部互联网络发送数据会产生位传播延迟,数据发送延迟,以及内部队列等待延迟。 影响内部网络延迟的因素有网络拓扑结构,数据的大小,以及网络响应速度等。 (2)内存带宽限制: 无论内存有多大,内存的数据交换和访问只能通过某一个单独的接口.而且一次只能处理一个字的读或者写操作。 (3)内存冲突: 当两个以上的处理器同时访问同一个内存模块时会造成内存冲突。 需要一个仲裁机制来决定在此种情况下由哪一个处理器优先获取访问权限。 (4)内存墙: 由于内存的读写速度远小于处理器的速度,内存墙便诞生了。 解决此问题的方法是使用多级内存,例如如下结构: 寄存器-高速缓存器-RAM-电子磁盘-磁盘-光盘 在并行处理器系统上运行一个并行算法时我们将会遇见多种延迟,详见表1.1. 假设某并行算法有N个独立的子任务,每个子任务都同时可以被一个或N个处理器执行,在此种理想条件下,由于每个子任务都是相对独立的,数据只需在处理器和内存之间交换.而不会出现处理器之间的数据交换.理想条件下可以得出如下等式: 单个处理器读取算法愉人数据所需时间为: 此等式中 表示内存访问某个数据块所需要的时间。 假设上述等式中的每个子任务都需要输人一个数据块,N个子任务需要输人N个数据块,则并行处理器从内存中读取数据的时间可以表示为: 表示共享内存受限访问因子。 当每个处理器都拥有一份自己需要的数侧备份时, =1/N.当由主存模块以此为每个子任务分配数据时 =1.在最坏的情况下 >N,此时每个处理器都需要从共享内存中读取数据,从而产生了内存冲突.可以把上述内容总结为: 若处理器试图访问同一组内存模块时,将结果写回内存也有可能发生冲突 对单一处理器而言,完成一个任务所需的时间(包括内存通信时间开销)表示如下: 考虑到通信开销的加速比计算等式如下: 内存不匹配比(R)的定义如下: R表示从内存读取一个数据块的延迟和处理一个数据块的延迟的比位.根据子任务的粒以及内存读写的速度不同, 应比 小几个数量级。 还可以将等式(1.17)用N和R表示为: 图展示了以N和R为参考量,在 =1的情况下加速比的变化情况。 数学模拟结果显示 的变化对结果并无显着影响。 由以上等式可知,在RN<<1的情况下可以得到最大的加速比,此结果与等式(1.7)中忽略通信开销的结论相符合。 此种情况发生时我们就称此算法是一个平凡并行算法,将在第7章详细讨论. 注意在RN>O.1时加速比开始迅速下降.当R=1时出现了通信边界问题,井行化的优势也消失了。 这提醒我们内存系统的设计和处理器之间的通信问题是很重要的。 第3章还会讨论多核处理器.由于多核处理器将处理单元都染成在一块芯片上,相比于跨芯片的多处理器系统,多核处理器的处理单元之间的通信速率拐到了大辐提升。 在多核系统中Tm减小了几个数量级,R值也大幅减小。 考虑内存的读写时间,多核处理器间的通信开销表示如下: 其中 》=0,由内存系统和算法决定. =0时表示单处理器系统,处理器之间无数据交换。 在某些算法中p的值可能等于log2N甚至等于N,其原因可能是程序员在编程时完全没有考虑到处理器之间的通信问题。 针对多处理器系统的Amdahl法则 假设一个算法或者一个任务
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 并行 计算 讲义