計(jì)算機(jī)程序設(shè)計(jì)并行計(jì)算概念及定義全面詳解
(本人剛剛完成這篇長文章的翻譯,尚未認(rèn)真校對。若里面有翻譯錯誤和打字錯誤敬請諒解,并請參考原貼)
1 摘要
帖子的原文: Introduction to Parallel Computing Tutorial
這篇帖子旨在為并行計(jì)算這一廣泛而宏大的話題提供一個非???/p>
速的概述,作為隨后教程的先導(dǎo)。因此,它只涵蓋了并行計(jì)算的基礎(chǔ)知識,實(shí)用于剛剛開始熟悉該主題的初學(xué)者。我們并不會深入討論并行計(jì)算,因?yàn)檫@將花費(fèi)大量的時間。本教程從對并行計(jì)算是什么以及如何使用開始,討論與其相關(guān)的概念和術(shù)語,然后解析并行內(nèi)存架構(gòu)(parallel memory architecture)以及編程模型(programming models)等。這些主題之后是一系列關(guān)于設(shè)計(jì)和運(yùn)行并行計(jì)算程序的復(fù)雜問題的實(shí)踐討論。最后,本教程給出了幾個并行化簡單串行程序的示例。
2 概述
2.1 什么是并行計(jì)算?
串行計(jì)算: 傳統(tǒng)的軟件通常被設(shè)計(jì)成為串行計(jì)算模式,具有如下特點(diǎn):
- 一個問題被分解成為一系列離散的指令;
- 這些指令被順次執(zhí)行;
- 所有指令均在一個處理器上被執(zhí)行;
- 在任何時刻,最多只有一個指令能夠被執(zhí)行。
例如,
并行計(jì)算: 簡單來講,并行計(jì)算就是同時使用多個計(jì)算資源來解決一個計(jì)算問題:
一個問題被分解成為一系列可以并發(fā)執(zhí)行的離散部分;
每個部分可以進(jìn)一步被分解成為一系列離散指令;
來自每個部分的指令可以在不同的處理器上被同時執(zhí)行;
需要一個總體的控制/協(xié)作機(jī)制來負(fù)責(zé)對不同部分的執(zhí)行情況進(jìn)行調(diào)度。
例如,
這里的 計(jì)算問題 需要具有如下特點(diǎn):
- 能夠被分解成為并發(fā)執(zhí)行離散片段;
- 不同的離散片段能夠被在任意時刻執(zhí)行;
- 采用多個計(jì)算資源的花費(fèi)時間要小于采用單個計(jì)算資源所花費(fèi)的時間。
這里的 計(jì)算資源 通常包括:
- 具有多處理器/多核(multiple processors/cores)的計(jì)算機(jī);
- 任意數(shù)量的被連接在一起的計(jì)算機(jī)。
并行計(jì)算機(jī):
通常來講,從硬件的角度來講,當(dāng)前所有的單機(jī)都可以被認(rèn)為是并行的:
- 多功能單元(L1緩存,L2緩存,分支,預(yù)取,解碼,浮點(diǎn)數(shù),圖形處理器,整數(shù)等)
- 多執(zhí)行單元/內(nèi)核
- 多硬件線程
IBM BG/Q Compute Chip with 18 cores (PU) and 16 L2 Cache units (L2)
通過網(wǎng)絡(luò)連接起來的多個單機(jī)也可以形成更大的并行計(jì)算機(jī)集群:
例如,下面的圖解就顯示了一個典型的LLNL并行計(jì)算機(jī)集群:
- 每個計(jì)算結(jié)點(diǎn)就是一個多處理器的并行計(jì)算機(jī);
- 多個計(jì)算結(jié)點(diǎn)用無限寬帶網(wǎng)絡(luò)連接起來;
- 某些特殊的結(jié)點(diǎn)(通常也是多處理器單機(jī))被用來執(zhí)行特定的任務(wù)。
2.2 為什么要并行計(jì)算?
真實(shí)世界就是高度并行的:
- 自然界中的萬事萬物都在并發(fā)的,按照其內(nèi)在時間序列運(yùn)行著;
- 和串行計(jì)算相比,并行計(jì)算更適用于對現(xiàn)實(shí)世界中的復(fù)雜現(xiàn)象進(jìn)行建模,模擬和理解;
- 例如,可以想象對這些進(jìn)行順序建模:
主要理由:
節(jié)約時間和成本:
1)理論上來講,在一個任務(wù)上投入更多的資源有利于縮短其完成時間,從而降低成本;
2)并行計(jì)算機(jī)可以由大量廉價的單機(jī)構(gòu)成,從而節(jié)約成本。
解決更大規(guī)模更復(fù)雜的問題:
1)很多問題的規(guī)模和復(fù)雜度使得其難以在一個單機(jī)上面完成;
2)一個有趣的例子:(Grand Challenge Problems)。
3)網(wǎng)頁搜索引擎/數(shù)據(jù)庫每秒處理百萬級別的吞吐量。
提供并發(fā)性:
1)單個計(jì)算資源某個時間段只能做一件事情,而多計(jì)算資源則可以同時做多件事情;
2)協(xié)同網(wǎng)絡(luò)可以使得來自世界不同地區(qū)的人同時虛擬地溝通。
利用非局部的資源:
1)可以利用更廣范圍中的網(wǎng)絡(luò)資源;
2)SETI@home的例子;
以及3)Folding@home的例子。
更好地利用并行硬件:
1)現(xiàn)代計(jì)算機(jī)甚至筆記本電腦在架構(gòu)上都屬于多處理器/多核的;
2)并行軟件已經(jīng)適用于多核的并行硬件條件,例如線程等;
3)在大多數(shù)情況下,運(yùn)行在現(xiàn)代計(jì)算機(jī)上的串行程序?qū)嶋H上浪費(fèi)了大量的計(jì)算資源。
并行計(jì)算的未來:
在過去的二十多年中,快速發(fā)展的網(wǎng)絡(luò),分布式系統(tǒng)以及多處理器計(jì)算機(jī)架構(gòu)(甚至在桌面機(jī)級別上)表明并行化才是計(jì)算的未來;
在同一時期,超級計(jì)算機(jī)的性能已經(jīng)有了至少50萬倍的增加,而且目前還沒有達(dá)到極限的跡象;
目前的峰值計(jì)算速度已經(jīng)達(dá)到了10181018/秒
2.3 誰都在使用并行計(jì)算?
科學(xué)界和工程界:
從歷史上來講,并行計(jì)算就被認(rèn)為是“計(jì)算的高端”,許多科學(xué)和工程領(lǐng)域的研究團(tuán)隊(duì)在對很多領(lǐng)域的問題建模上都采用了并行計(jì)算這一模式,包括:大氣與地球環(huán)境、應(yīng)用物理、生物科學(xué)、遺傳學(xué)、化學(xué)、分子科學(xué)、機(jī)械工程、電氣工程、計(jì)算機(jī)科學(xué)、數(shù)學(xué)、國防和武器研發(fā)等。
工業(yè)界和商業(yè)界:
如今,商業(yè)應(yīng)用為更快速計(jì)算機(jī)的研發(fā)提供了更強(qiáng)勁的動力。這些商業(yè)應(yīng)用程序需要以更復(fù)雜的方式處理大量數(shù)據(jù),例如:大數(shù)據(jù)、數(shù)據(jù)庫、數(shù)據(jù)挖掘、石油勘探、網(wǎng)頁搜索引擎、基于web的商業(yè)服務(wù)、醫(yī)學(xué)成像和診斷、跨國公司管理、高級圖形學(xué)技術(shù)以及虛擬現(xiàn)實(shí)、網(wǎng)絡(luò)視頻和多媒體技術(shù)、協(xié)同工作環(huán)境等。
全球應(yīng)用:
并行計(jì)算目前在實(shí)際上被廣泛采用于大量應(yīng)用中
3 概念和術(shù)語
3.1 馮諾依曼體系結(jié)構(gòu)
以匈牙利數(shù)學(xué)家約翰·馮諾依曼命名的這一計(jì)算機(jī)體系結(jié)構(gòu),出現(xiàn)在他1945年發(fā)表的一篇論文中。這也通常被稱為“存儲程序計(jì)算機(jī)”——程序指令和數(shù)據(jù)都被保存在存儲器中,這與早期通過“硬接線”編程的計(jì)算機(jī)不同。從此以后,所有的計(jì)算機(jī)走遵從這一基本架構(gòu):
- 四個組成部分:1)內(nèi)存;2)控制器;3)處理器;4)輸入輸出。
- 讀寫操作:支持隨機(jī)存儲的內(nèi)存用來同時保存程序指令和數(shù)據(jù):
1)程序指令用來指導(dǎo)計(jì)算機(jī)操作;
2)數(shù)據(jù)是程序用來操作的對象。
- 控制器:從內(nèi)存中讀取指令或者數(shù)據(jù),對這些指令進(jìn)行解碼并且順序執(zhí)行這些指令。
- 處理器:提供基本的算術(shù)和邏輯操作。
- 輸入輸出設(shè)備:是人機(jī)交互的接口。
那么馮諾依曼體系結(jié)構(gòu)和并行計(jì)算有什么關(guān)系呢?答案是:并行計(jì)算機(jī)仍然遵從這一基本架構(gòu),只是處理單元多于一個而已,其它的基本架構(gòu)完全保持不變。
3.2 弗林的經(jīng)典分類
有不同的方法對并行計(jì)算機(jī)進(jìn)行分類(具體例子可參見并行計(jì)算分類)。
一種被廣泛采用的分類被稱為弗林經(jīng)典分類,誕生于1966年。弗林分類法從指令流和數(shù)據(jù)流兩個維度區(qū)分多處理器計(jì)算機(jī)體系結(jié)構(gòu)。每個維度有且僅有兩個狀態(tài):單個或者多個。
下面?zhèn)€矩陣定義了弗林分類的四個可能狀態(tài):
單指令單數(shù)據(jù)(SISD): SISD是標(biāo)準(zhǔn)意義上的串行機(jī),具有如下特點(diǎn):
1)單指令:在每一個時鐘周期內(nèi),CPU只能執(zhí)行一個指令流;
2)單數(shù)據(jù):在每一個時鐘周期內(nèi),輸入設(shè)備只能輸入一個數(shù)據(jù)流;
3)執(zhí)行結(jié)果是確定的。這是最古老的一種計(jì)算機(jī)類型。
單指令多數(shù)據(jù)(SIMD): SIMD屬于一種類型的并行計(jì)算機(jī),具有如下特點(diǎn):
1)單指令:所有處理單元在任何一個時鐘周期內(nèi)都執(zhí)行同一條指令;
2)多數(shù)據(jù):每個處理單元可以處理不同的數(shù)據(jù)元素;
3)非常適合于處理高度有序的任務(wù),例如圖形/圖像處理;
4)同步(鎖步)及確定性執(zhí)行;
5)兩個主要類型:處理器陣列和矢量管道。
多指令單數(shù)據(jù)(MISD):MISD屬于一種類型的并行計(jì)算機(jī),具有如下特點(diǎn):
1)多指令:不同的處理單元可以獨(dú)立地執(zhí)行不同的指令流;
2)單數(shù)據(jù):不同的處理單元接收的是同一單數(shù)據(jù)流。這種架構(gòu)理論上是有的,但是工業(yè)實(shí)踐中這種機(jī)型非常少。
多指令多數(shù)據(jù)(MIMD): MIMD屬于最常見的一種類型的并行計(jì)算機(jī),具有如下特點(diǎn):
1)多指令:不同的處理器可以在同一時刻處理不同的指令流;
2)多數(shù)據(jù):不同的處理器可以在同一時刻處理不同的數(shù)據(jù);
3)執(zhí)行可以是同步的,也可以是異步的,可以是確定性的,也可以是不確定性的。這是目前主流的計(jì)算機(jī)架構(gòu)類型,目前的超級計(jì)算機(jī)、并行計(jì)算機(jī)集群系統(tǒng),網(wǎng)格,多處理器計(jì)算機(jī),多核計(jì)算機(jī)等都屬于這種類型。
值得注意的是,許多MIMD類型的架構(gòu)中實(shí)際也可能包括SIMD的子架構(gòu)。
3.3 一些常見的并行計(jì)算術(shù)語
和其它一些領(lǐng)域一樣,并行計(jì)算也有自己的“術(shù)語”。下面列出了與并行計(jì)算相關(guān)聯(lián)的一些常用術(shù)語,其中大部分術(shù)語我們在后面還會進(jìn)行更詳細(xì)的討論。
- 結(jié)點(diǎn)(Node):
也就是一個獨(dú)立的“計(jì)算機(jī)單元”。通常由多個CPU處理器/處理內(nèi)核,內(nèi)存,網(wǎng)絡(luò)接口等組成。結(jié)點(diǎn)聯(lián)網(wǎng)在一起以構(gòu)成超級計(jì)算機(jī)。
- 中央處理器/套接字/處理器/核(CPU / Socket / Processor / Core):
這些術(shù)語也取決于我們討論的語境。在過去,中央處理器通常是計(jì)算機(jī)中的一個單個執(zhí)行單元。之后多處理器被植入到一個結(jié)點(diǎn)中。接著處理器又被設(shè)計(jì)成為多核,每個核成為一個獨(dú)立的處理單元。具有多核的中央處理器有時候又被稱為“套接字”——實(shí)際上也沒有統(tǒng)一標(biāo)準(zhǔn)。所以目前來講,我們稱一個結(jié)點(diǎn)上具有多個中央處理器,每個中央處理器上又具有多個內(nèi)核。
- 任務(wù)(Task):
任務(wù)通常是指一個邏輯上離散的計(jì)算工作部分。一個任務(wù)通常是一段程序或者一段類似于程序的指令集合,可以由一個處理器進(jìn)行處理。一個并行程序通常由多個任務(wù)構(gòu)成,并且可以運(yùn)行在多個處理器上。
- 流水線(Pipelining):
可以將任務(wù)分解成為不同的步驟,并且由不同的處理單元完成,里面有輸入流通過。這非常類似于一個裝配線,屬于一種類型的并行計(jì)算。
- 共享內(nèi)存(Shared Memory):
從嚴(yán)格的硬件角度來講,共享內(nèi)存描述了一種計(jì)算機(jī)架構(gòu),其中所有的處理器都可以對共同的物理內(nèi)存進(jìn)行直接存?。ㄍǔJ峭ㄟ^總線)。從編程的角度來講,共享內(nèi)存描述了一種模型,其中所有的并行任務(wù)都具有同一內(nèi)存形態(tài),并且都可以直接對同一內(nèi)存區(qū)域進(jìn)行直接定位和存取,而無論該物理內(nèi)存實(shí)際上在哪里(也許在千里之外的另外一個計(jì)算機(jī)上?)。
- 對稱多處理器(Symmetric Multi-Processor (SMP)):
屬于一種共享內(nèi)存的硬件架構(gòu),并且不同的處理器對內(nèi)存以及其它資源都具有同等的訪問權(quán)限(個人理解,就是不同處理器在角色上沒有任何區(qū)別)。
- 分布式內(nèi)存(Distributed Memory):
在硬件中,表示基于網(wǎng)絡(luò)的內(nèi)存存取方式;在編程模型中,表示任務(wù)僅僅能夠從邏輯上“看到”本機(jī)上的內(nèi)存,但是在其它任務(wù)執(zhí)行的時候,必須通過通訊才能對其它任務(wù)所運(yùn)行的機(jī)器上的內(nèi)存進(jìn)行存取。
- 通訊(communications):
并行任務(wù)通常需要數(shù)據(jù)交換。實(shí)現(xiàn)數(shù)據(jù)交換的方式有多種,例如通過共享內(nèi)存或者通過網(wǎng)絡(luò)。但是通常意義上,數(shù)據(jù)交換指的就是通訊,而無論其實(shí)現(xiàn)方式。
- 同步(Synchronization):
指的是并行任務(wù)之間的實(shí)時協(xié)調(diào),通常伴隨著通訊(communication)。同步通常由在程序中設(shè)立同步點(diǎn)來實(shí)現(xiàn),也就是說,在其它任務(wù)沒有執(zhí)行到這一同步點(diǎn)的時候,某一任務(wù)不能進(jìn)一步執(zhí)行后面的指令。同步通常涉及到需要等待其它任務(wù)的完成,因此有時候會增加并行程序的執(zhí)行時間。
- 粒度(Granularity):
在并行計(jì)算中,粒度定量地描述了計(jì)算與通訊的比率。粗粒度表示在通訊過程中需要做大量的計(jì)算性工作;細(xì)粒度則表示在通訊過程中需要做的計(jì)算性工作并不多。
- 加速比(Observed Speedup):
這是檢測并行計(jì)算性能的最簡單并且最被廣泛使用的度量策略,其定義如下:串行計(jì)算的時鐘周期數(shù)并行計(jì)算的時鐘周期數(shù)串行計(jì)算的時鐘周期數(shù)并行計(jì)算的時鐘周期數(shù)。
- 并行開銷(Parallel Overhead):
指的是相對于做實(shí)際計(jì)算,做協(xié)調(diào)并行任務(wù)所需要花費(fèi)的時間總數(shù)。影響并行開銷的因素主要包括:
1)任務(wù)啟動時間;
2)同步;
3)數(shù)據(jù)通訊;
4)由并行語言,鏈接庫,操作系統(tǒng)等因素而導(dǎo)致的軟件開銷;
5)任務(wù)終止時間。
- 大規(guī)模并行(Massive Parallel):
指那些包含并行系統(tǒng)的硬件——擁有很多的處理元件。這里的“很多”可能會隨著硬件條件的進(jìn)步而不斷增加,但目前,最大的并行系統(tǒng)所擁有的處理元件高達(dá)上百萬件。
- 尷尬并行(Embarrassingly Parallel):
指的是同時解決很多類似而又獨(dú)立的任務(wù),其中任務(wù)之間幾乎沒有需要協(xié)調(diào)的地方。
- 可擴(kuò)展性(Scalability):
指的是并行系統(tǒng)(包括軟件和硬件)通過添加更多資源來成比例增加并行速度的能力。影響可擴(kuò)展性的因素主要包括:
1)硬件,尤其是內(nèi)存-處理器帶寬以及網(wǎng)絡(luò)通訊的質(zhì)量和速度;
2)應(yīng)用算法;
3)相對并行開銷;
4)具體應(yīng)用的特征。
3.4 并行程序的缺陷和代價
阿姆達(dá)爾定律: 阿姆達(dá)爾定律說一個程序的加速比潛力由其可以并行的部分所占的比例而決定,即:
speedup=11−Pspeedup=11−P.
如果沒有代碼可以被并行,那么p = 0,所以加速比為1。如果所有的代碼都可以被并行,那么 p = 1,加速比為無窮大(當(dāng)然只是理論上而言)。如果50%的代碼可以被并行,那么最大的加速比為2,意味著的運(yùn)行速度最快可以被加速到2倍。
如果引入并行程序中的處理器個數(shù),則加速比可以被重新定義為:
speedup=1PN+S=11−P+PNspeedup=1PN+S=11−P+PN,
其中P仍然是并行代碼所占的比例,N是處理器個數(shù),S是串行代碼所占比例(S = 1 - P)。
N | P = 0.50 | p = 0.90 | p = 0.95 | p = 0.99 |
---|---|---|---|---|
10 | 1.82 | 5.26 | 6.89 | 9.17 |
100 | 1.98 | 9.17 | 16.80 | 50.25 |
1000 | 1.99 | 9.91 | 19.62 | 90.99 |
10000 | 1.99 | 9.91 | 19.96 | 99。02 |
100000 | 1.99 | 9.99 | 19.99 | 99.90 |
之后我們就迅速意識到并行計(jì)算的極限所在,例如上表所示。
“注明引言:”你可以花費(fèi)一生的時間使得你的代碼的95%都可以被并行,然而你如論投入多少處理器,都不會獲得20倍的加速比。
然而,某些問題我們可以通過增加問題的大小來提高其性能。例如:
類型 | 時間 | 比例 |
---|---|---|
2D網(wǎng)格計(jì)算 | 85秒 | 85% |
串行比例 | 15秒 | 15% |
我們可以增加網(wǎng)格的維度,并且將時間步長減半。其結(jié)果是四倍的網(wǎng)格點(diǎn)數(shù)量,以及兩倍的時間步長。之后的花費(fèi)時間將變?yōu)椋?/p>
類型 | 時間 | 比例 |
---|---|---|
2D網(wǎng)格計(jì)算 | 680秒 | 97.84% |
串行比例 | 15秒 | 2.16% |
復(fù)雜性:
通常而言,并行計(jì)算的程序要比相應(yīng)的串行計(jì)算程序更加復(fù)雜,也許復(fù)雜一個量級。你不僅需要同時執(zhí)行不同的指令流,而且需要注意他們之間數(shù)據(jù)的通信。復(fù)雜性通常由涉及軟件開發(fā)周期各個方面的時間來確定,主要包括:
1)設(shè)計(jì);2)編碼;3)調(diào)試;4)調(diào)參;5)維護(hù)。
遵循良好的軟件開發(fā)實(shí)踐對并行應(yīng)用開發(fā)是至關(guān)重要的,尤其是在除你之外的其他人還需要和你合作的情況下。
可移植性:
由于一些API的標(biāo)準(zhǔn)化,例如MPI,POSIX線程以及OpenMP,并行程序的可移植性問題并不像過去那么嚴(yán)重,然而:
- 所有串行程序中所遇到的可移植性問題都會出現(xiàn)在相應(yīng)的并行程序中。
- 盡管一些API已經(jīng)被標(biāo)準(zhǔn)話,但是在一些細(xì)節(jié)的實(shí)現(xiàn)上任然有差異,有時候這些細(xì)節(jié)實(shí)現(xiàn)會影響到可移植性。
- 操作系統(tǒng)也會是導(dǎo)致可移植性的關(guān)鍵因素。
- 硬件架構(gòu)的不同有時候也會影響到可移植性。
資源需求:
并行編程的主要目標(biāo)就是降低時鐘等待時間。然而要做到這一點(diǎn),需要更多的CPU時間。例如,一個在8個處理器上跑了一個小時的并行程序?qū)嶋H上花費(fèi)了8小時的CPU時間。
并行程序所需要的內(nèi)存開銷往往要大于相對應(yīng)的串行程序,這是因?yàn)槲覀冇袝r候需要復(fù)制數(shù)據(jù),以滿足庫和子系統(tǒng)對并行算法的要求。
對于運(yùn)行時間較短的并行陳顧,實(shí)際性能反而有可能比相對應(yīng)的串行程序有所降低。這是由于并行環(huán)境的建立,任務(wù)創(chuàng)建,通訊,任務(wù)結(jié)束等在這個運(yùn)行時間中有可能會占有比較大的比例。
可擴(kuò)展性:
基于時間和解決方案的不同,可以將擴(kuò)展性分為強(qiáng)可擴(kuò)展性和弱可擴(kuò)展性:
強(qiáng)可擴(kuò)展性的特點(diǎn)是:
1)在更多處理器被加入的時候,問題本身的規(guī)模不會增加;
2)目標(biāo)是將同一問題運(yùn)行的更快;
3)理想狀態(tài)下,相比于對應(yīng)的串行程序,運(yùn)行時間為1/P。
弱可擴(kuò)展性的特點(diǎn)是:
1)隨著更多處理器被加入,每個處理上需要處理的問題規(guī)模保持一致;
2)目標(biāo)是在相同的時間內(nèi)解決更多規(guī)模的問題;
3)理想狀態(tài)下,在相同時間內(nèi),可以解決的問題規(guī)模增加為原問題規(guī)模的P倍。
并行程序的性能提高取決于一系列相互依賴的因素,簡單地增加更多的處理器并不一定是唯一的方法。
此外,某些問題可能本身存在擴(kuò)展性的極限,因此添加更多的資源有時候反而會降低性能。這種情形會出現(xiàn)在很多并行程序中。
硬件在可擴(kuò)展性方面也扮演者重要角色,例如:1)內(nèi)存-CPU之間的帶寬;2)通訊網(wǎng)絡(luò)的帶寬;3)某個機(jī)器或者某個機(jī)器集合中的內(nèi)存大?。?)時鐘處理速度。
支持并行的庫或者子系統(tǒng)同樣也會限制并行程序的可擴(kuò)展性。
4 并行計(jì)算機(jī)的內(nèi)存架構(gòu)
4.1 共享內(nèi)存
一般特征:
共享內(nèi)存的并行計(jì)算機(jī)雖然也分很多種,但是通常而言,它們都可以讓所有處理器以全局尋址的方式訪問所有的內(nèi)存空間。多個處理器可以獨(dú)立地操作,但是它們共享同一片內(nèi)存。一個處理器對內(nèi)存地址的改變對其它處理器來說是可見的。根據(jù)內(nèi)存訪問時間,可以將已有的共享內(nèi)存機(jī)器分為統(tǒng)一內(nèi)存存取和非統(tǒng)一內(nèi)存存取兩種類型。
統(tǒng)一內(nèi)存存取(Uniform Memory Access):
目前更多地被稱為對稱多處理器機(jī)器(Symmetric Multiprocessor (SMP)),每個處理器都是相同的,并且其對內(nèi)存的存取和存取之間都是無差別的。有時候也會被稱為CC-UMA (Cache coherent - UMA)。緩存想干意味著如果一個處理器更新共享內(nèi)存中的位置,則所有其它處理器都會了解該更新。緩存一致性是在硬件級別上實(shí)現(xiàn)的。
非統(tǒng)一內(nèi)存存取(Non-Uniform Memory Access):
通常由兩個或者多個物理上相連的SMP。一個SMP可以存取其它SMP上的內(nèi)存。不是所有處理器對所有內(nèi)存都具有相同的存取或者存取時間。通過連接而進(jìn)行內(nèi)存存取速度會更慢一些。如果緩存相緩存想干的特性在這里仍然被保持,那么也可以被稱為CC-NUMA。
優(yōu)點(diǎn):
全局地址空間提供了一種用戶友好的編程方式,并且由于內(nèi)存與CPU的階級程度,使得任務(wù)之間的數(shù)據(jù)共享既快速又統(tǒng)一。
缺點(diǎn):
最大的缺點(diǎn)是內(nèi)存和CPU之間缺少較好的可擴(kuò)展性。增加更多的CPU意味著更加共享內(nèi)存和緩存想干系統(tǒng)上的存取流量,從而幾何級別地增加緩存/內(nèi)存管理的工作量。同時也增加了程序員的責(zé)任,因?yàn)樗枰_保全局內(nèi)存“正確”的訪問以及同步。
4.2 分布式內(nèi)存
一般概念: 分布式內(nèi)存架構(gòu)也可以分為很多種,但是它們?nèi)匀挥幸恍┕餐卣鳌7植际絻?nèi)存結(jié)構(gòu)需要通訊網(wǎng)絡(luò),將不同的內(nèi)存連接起來。一般而言,處理器會有它們所對應(yīng)的內(nèi)存。一個處理器所對應(yīng)的內(nèi)存地址不會映射到其它處理器上,所以在這種分布式內(nèi)存架構(gòu)中,不存在各個處理器所共享的全局內(nèi)存地址。
由于每個處理器具有它所對應(yīng)的局部內(nèi)存,所以它們可以獨(dú)立進(jìn)行操作。一個本地內(nèi)存上所發(fā)生的變化并不會被其它處理器所知曉。因此,緩存想干的概念在分布式內(nèi)存架構(gòu)中并不存在。
如果一個處理器需要對其它處理器上的數(shù)據(jù)進(jìn)行存取,那么往往程序員需要明確地定義數(shù)據(jù)通訊的時間和方式,任務(wù)之間的同步因此就成為程序員的職責(zé)。盡管分布式內(nèi)存架構(gòu)中用于數(shù)據(jù)傳輸?shù)木W(wǎng)絡(luò)結(jié)構(gòu)可以像以太網(wǎng)一樣簡單,但在實(shí)踐中它們的變化往往也很大。
優(yōu)點(diǎn):
1)內(nèi)存可以隨著處理器的數(shù)量而擴(kuò)展,增加處理器的數(shù)量的同時,內(nèi)存的大小也在成比例地增加;
2)每個處理器可以快速地訪問自己的內(nèi)存而不會受到干擾,并且沒有維護(hù)全局告訴緩存一致性所帶來的開銷;
3)成本效益:可以使用現(xiàn)有的處理器和網(wǎng)絡(luò)。
缺點(diǎn):
1)程序員需要負(fù)責(zé)處理器之間數(shù)據(jù)通訊相關(guān)的許多細(xì)節(jié);
2)將基于全局內(nèi)存的現(xiàn)有數(shù)據(jù)結(jié)構(gòu)映射到該分布式內(nèi)存組織可能會存在困難;
3)非均勻的內(nèi)存訪問時間——駐留在遠(yuǎn)程結(jié)點(diǎn)上的數(shù)據(jù)比本地結(jié)點(diǎn)上的數(shù)據(jù)需要長的多的訪問時間。
4.3 混合分布式-共享內(nèi)存
一般概念: 目前世界上最大和最快的并行計(jì)算機(jī)往往同時具有分布式和共享式的內(nèi)存架構(gòu)。共享式內(nèi)存架構(gòu)可以是共線內(nèi)存機(jī)器或者圖形處理單元(GPU)。分布式內(nèi)存組件可以是由多個共享內(nèi)存/GPU連接而成的系統(tǒng)。每個結(jié)點(diǎn)只知道自己的內(nèi)存,不知道網(wǎng)絡(luò)上其它結(jié)點(diǎn)的內(nèi)存。因此,需要在不同的機(jī)器上通過網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)通訊。
從目前的趨勢來看,這種混合式的內(nèi)存架構(gòu)將長期占有主導(dǎo)地位,并且成為高端計(jì)算在可見的未來中的最好選擇。
優(yōu)缺點(diǎn):
1)繼承了共享式內(nèi)存和分布式內(nèi)存的優(yōu)缺點(diǎn);
2)優(yōu)點(diǎn)之一是可擴(kuò)展性;
3)缺點(diǎn)之一是編程的復(fù)雜性。
5. 并行計(jì)算模型
5.1 概述
常見的并行編程模型包括:共享內(nèi)存模型(無線程),線程模型,分布式內(nèi)存/消息傳遞模型,數(shù)據(jù)并行模型,混合模型,單程序多數(shù)據(jù)模型,多程序多數(shù)據(jù)模型。
并行計(jì)算模型是作為硬件和內(nèi)存架構(gòu)之上的一種抽象存在。雖然不一定顯而易見,但這些模型并不和特定的機(jī)器和內(nèi)存架構(gòu)有關(guān)。事實(shí)上,任何一個并行計(jì)算模型從理論上來講都可以實(shí)現(xiàn)在任何一種硬件上。下面是兩個例子。
在分布式內(nèi)存架構(gòu)上的共享內(nèi)存模型
機(jī)器內(nèi)存分布于網(wǎng)絡(luò)上的不同結(jié)點(diǎn),但是對于用戶而言,看到的確實(shí)一個具有全局地址空間的共享內(nèi)存。這種方法通常被稱為“虛擬共享存儲器”。
在共享內(nèi)存架構(gòu)上的分布式內(nèi)存模型
最主要的是消息傳遞接口(MPI)。每個任務(wù)都可以直接訪問跨所有機(jī)器的全局地址空間。然而,它們之間數(shù)據(jù)交換卻是通過消息傳遞機(jī)制實(shí)現(xiàn)的,就像在分布式內(nèi)存網(wǎng)絡(luò)中所進(jìn)行的那樣。
那么到底使用哪一種呢?這往往取決于現(xiàn)有條件以及用戶的偏好。沒有最好的模型,但對模型的實(shí)現(xiàn)質(zhì)量卻可能存在差別。下面我們將分別描述上面提到的各種并行計(jì)算模型,并且討論它們在實(shí)踐中的一些實(shí)現(xiàn)方式。
5.2 共享內(nèi)存模型(無線程)
在這種并行計(jì)算模型中,處理器/任務(wù)共享內(nèi)存空間,并且可以異步地對內(nèi)存進(jìn)行讀寫。很多機(jī)制被用來控制對內(nèi)存的存取,例如鎖/信號量等,用來解決訪問沖突以及避免死鎖。這應(yīng)該是最簡單的并行計(jì)算模型了。
從編程者的角度來看,這種模型的好處之一數(shù)據(jù)“擁有者”的缺失,所以他們不必明確地指定數(shù)據(jù)之間的通訊。所有的處理器都可以看到和平等地存取共享內(nèi)存。程序開發(fā)將因此而變得容易。
性能方面的一個重要缺點(diǎn)是對數(shù)據(jù)局部性的理解和管理講變得困難:1)保持?jǐn)?shù)據(jù)的局部性將有利于減少內(nèi)存的存取負(fù)擔(dān),緩存刷新次數(shù)以及總線流量。而當(dāng)多個處理器使用同一數(shù)據(jù)時,這些負(fù)擔(dān)將會經(jīng)常發(fā)生;2)不幸的是,保持?jǐn)?shù)據(jù)的局部性往往比較難以理解,并且其難度超過一般用戶的水平。
實(shí)現(xiàn): 單機(jī)共享內(nèi)存機(jī)器,本地操作系統(tǒng),編譯器及其對應(yīng)的硬件都支持共享內(nèi)存編程。在分布式內(nèi)存機(jī)器上,內(nèi)存在物理上存在于網(wǎng)絡(luò)上不同的結(jié)點(diǎn)上,但是可以通過特殊的硬件和軟件,將其變?yōu)槿挚梢姟?/p>
5.3 線程模型
這是共享內(nèi)存編程的一種模式。在線程模型中,一個單個的“重量級”進(jìn)程可以擁有多個“輕量級”的并發(fā)執(zhí)行路徑。例如下圖所示:
- 主程序 a.out 在本地操作系統(tǒng)上運(yùn)行。a.out 需要加載所有的系統(tǒng)和用戶資源來運(yùn)行,這是里面的“重量級”進(jìn)程。a.out 首先執(zhí)行一些串行工作,然后生成一系列任務(wù)(線程),而這些線程可以在操作系統(tǒng)中被并發(fā)地執(zhí)行。
- 每個線程具有本地?cái)?shù)據(jù),但同時也共享 a.out 的所有資源。這節(jié)約了所有線程都復(fù)制程序資源的的開銷。而每個線程同時也從全局內(nèi)存中獲益,因?yàn)樗梢怨蚕?a.out 的內(nèi)存空間。
- 一個線程的工作可以被描述為主程序的一個子程序。任何線程都可以在其它線程運(yùn)行的同時執(zhí)行任何子程序。
- 線程之間的通訊通過全局內(nèi)存來實(shí)現(xiàn)(對全局地址的更新)。這需要建立一種同步機(jī)制,以保證在同一時刻,不會有多個線程對同一塊地址空間進(jìn)行更新。
- 線程可以隨時生成和結(jié)束,但是 a.out 卻一直存在,以提供所需的共享資源,直到整個應(yīng)用程序結(jié)束。
實(shí)現(xiàn): 從編程的角度來講,線程的實(shí)現(xiàn)通常包括如下兩個方面:
- 庫函數(shù)或者子程序,這些庫函數(shù)或者子程序可以在并行源代碼中被調(diào)用;
- 嵌入在并行或者串行源代碼中的一組編譯器指令集合。
程序員需要同時定義上面的兩個方面(盡管有時候編譯器可以提供幫助)。
線程并不是一個新概念。之前硬件供應(yīng)商就曾經(jīng)實(shí)現(xiàn)過他們自己的線程。由于這些線程的實(shí)現(xiàn)各不相同,所以使得程序員很難開發(fā)可移植的多線程應(yīng)用程序。
而標(biāo)準(zhǔn)化工作卻導(dǎo)致了兩種完全不同的線程實(shí)現(xiàn)方式:POSIX Threads 和 OpenMP。
POSIX Threads:
由IEEE POSIX 1003.1c standard (1995)定義,僅支持C語言,是Unix/Linux操作系統(tǒng)的一部分,是基于庫函數(shù)的,也通常被稱為“Pthreads”。是非常明確的并行機(jī)制,需要程序員注意大量的細(xì)節(jié)。更多信息可見:POSIX Threads tutorial。
OpenMP:
是一個工業(yè)標(biāo)準(zhǔn),有一組主要計(jì)算機(jī)硬件和軟件提供商,組織和個人聯(lián)合發(fā)起和定義,是基于編譯器指令的,具有可移植性/跨平臺性,目前支持的包括Unix和Windows平臺,目前支持C/C++和Fortran語言。非常簡單和醫(yī)用,提供了“增量并行”,可以從串行代碼開始。更多信息可見:OpenMP tutorial。
也有一些其它的常見線程實(shí)現(xiàn),但是在這里沒有討論,包括:
Microsoft threads
Java, Python threads
CUDA threads for GPUs
5.4 分布式內(nèi)存/消息傳遞模型
這種模型具有如下特點(diǎn):
- 在計(jì)算的過程中,每個任務(wù)都僅僅使用它們自身的本地內(nèi)存。多個任務(wù)既可以寄宿在同一個物理機(jī)器上,也可以跨越不同的物理機(jī)器。
- 任務(wù)之間的數(shù)據(jù)交換是通過發(fā)送和接收消息而實(shí)現(xiàn)的。
- 數(shù)據(jù)傳輸通常需要不同進(jìn)程之間的協(xié)同操作才能實(shí)現(xiàn)。例如,一個發(fā)送操作需要同時對應(yīng)一個接收操作。
實(shí)現(xiàn): 從編程的角度來講,消息傳遞的實(shí)現(xiàn)通常包括子程序庫。對這些子程序的調(diào)用往往就嵌入在源代碼中。編程者負(fù)責(zé)并行機(jī)制的實(shí)現(xiàn)。
自從1980年代以來,出現(xiàn)了多種消息傳遞庫函數(shù)。這些實(shí)現(xiàn)各不相同,導(dǎo)致編程者很難開發(fā)出移植性好的應(yīng)用程序。自從1992年開始,MPI Forum形成,其主要目標(biāo)是建立消息傳遞的標(biāo)準(zhǔn)接口。消息傳遞接口(Message Passing Interface (MPI))的第一部分在1994年發(fā)布,第二部分在1996年發(fā)布,第三部分在2012年發(fā)布。所有的MPI說明可以參見 MPI Documents
。MPI成為了事實(shí)上的消息傳遞的工業(yè)標(biāo)準(zhǔn),取代了所有其它消息傳遞的實(shí)現(xiàn)。幾乎所有流行的并行計(jì)算平臺都存在MPI的實(shí)現(xiàn),但并不是所有的實(shí)現(xiàn)都包含了MPI-1,MPI-2和MPI-3的所有內(nèi)容。關(guān)于MPI的更多信息可以參見 MPI tutorial。
5.5 數(shù)據(jù)并行模型
通常也被稱為“全局地址空間分區(qū)”(Partitioned Global Address Space (PGAS))模型。具有如下特點(diǎn):
- 地址空間被認(rèn)為是全局的。
- 大多數(shù)的并行工作聚焦于在數(shù)據(jù)集上的操作。數(shù)據(jù)集通常被組織成為常用的結(jié)構(gòu),例如數(shù)組,數(shù)立方等。
- 一系列任務(wù)在同一塊數(shù)據(jù)結(jié)構(gòu)上操作,但是每個任務(wù)卻操作在該數(shù)據(jù)結(jié)構(gòu)的不同分區(qū)上。
- 每個任務(wù)在數(shù)據(jù)結(jié)構(gòu)的不同分區(qū)上執(zhí)行相同的操作,例如,“給每個數(shù)組元素加上4”。
在共享內(nèi)存的架構(gòu)下,所有的任務(wù)通過全局內(nèi)存方式來對數(shù)據(jù)進(jìn)行存??;在分布式內(nèi)存架構(gòu)下,根據(jù)任務(wù)分配,全局?jǐn)?shù)據(jù)結(jié)構(gòu)在物理或者邏輯上被進(jìn)行分割。
實(shí)現(xiàn): 目前,基于數(shù)據(jù)并行/PGAS模型,有如下幾個相對有名的實(shí)現(xiàn):
Coarray Fortran
: 為了支持SPMD并行編程而在Fortran 95上做的一個小的擴(kuò)展,是編譯器相關(guān)的,更多信息可以參見: Coarray_Fortran
Unified Parallel C (UPC)
: 為了支持SPMD并行編程而在C語言基礎(chǔ)上做的擴(kuò)展,也是編譯器相關(guān)的,更多信息可以參見: The UPC Language
5.6 混合模型
混合模型指的是包含了至少兩個我們前面提到的并行計(jì)算模型的模型。目前,最常見的混合模型的例子是消息傳遞模型(MPI)和線程模型(OpenMP)的結(jié)合:
- 線程使用本地?cái)?shù)據(jù)完成計(jì)算密集型的任務(wù);
- 不同的進(jìn)程則在不同的結(jié)點(diǎn)上通過MPI完成數(shù)據(jù)通訊。
這種混合模型非常適合目前流行的硬件環(huán)境——多核計(jì)算機(jī)組成的集群系統(tǒng)。
另外一種類似的,但原來越流行的例子是采用MPI和CPU-GPU的混合編程:
- 采用MPI的任務(wù)運(yùn)行于CPU上,使用本地內(nèi)存上的數(shù)據(jù),但是通過網(wǎng)絡(luò)與其它任務(wù)進(jìn)行數(shù)據(jù)交換;
- 而計(jì)算密集型的核則被加載到GPU上進(jìn)行計(jì)算;
- 而結(jié)點(diǎn)內(nèi)部的內(nèi)存和GPU上的數(shù)據(jù)交換則通過CUDA(或者類似的東西)進(jìn)行數(shù)據(jù)交換。
其它混合模型還包括:
- MPI和Pthreads的混合;
- MPI和non-GPU加速器的混合。
- …
5.7 單程序多數(shù)據(jù)模型(SPMD)和多程序多數(shù)據(jù)模型(MPMD)
單程序多數(shù)據(jù)模型(Single Program Multiple Data (SPMD)):
SPMD事實(shí)上是一種可以架構(gòu)在其它并行編程模型之上的更“高級”的編程模型:
- 單程序:所有任務(wù)都執(zhí)行同一個程序的拷貝,而這里的程序可以是線程,消息傳遞,數(shù)據(jù)并行甚至混合;
- 多數(shù)據(jù):不同的任務(wù)操作于不同的數(shù)據(jù)。
SMPD通常需要指定任務(wù)的執(zhí)行邏輯,也就是不同的任務(wù)可能會根據(jù)分支和邏輯關(guān)系,去執(zhí)行整個程序的某個部分,也就是說,不是所有的任務(wù)都必須執(zhí)行整個程序——有可能只是整個程序的某個部分。(譯者注:如果不強(qiáng)調(diào)這一點(diǎn),SPMD就退化成了數(shù)據(jù)并行模型了。)
而這種采用消息消息傳遞或者混合編程的SPMD模型,有可能是今天運(yùn)行在多核集群系統(tǒng)上的最常見的并行計(jì)算模型了。
多程序多數(shù)據(jù)模型(Multiple Program Multiple Data (MPMD)):
和SPMD一樣,多程序多數(shù)據(jù)模型實(shí)際上也是一種可以架構(gòu)在其它并行編程模型基礎(chǔ)上的“高級”并行編程模型:
- 多程序:任務(wù)可以同時執(zhí)行不同的程序,這里的程序可以是線程,消息傳遞,數(shù)據(jù)并行或者它們的混合。
- 多數(shù)據(jù):所有的任務(wù)可以使用不同的數(shù)據(jù)。
MPMD應(yīng)用并不像SPMD應(yīng)用那么常見,但是它可能更適合于特定類型的程序。
6 并行程序設(shè)計(jì)
6.1 自動 vs. 手動并行化
設(shè)計(jì)和實(shí)現(xiàn)并行程序是一個非常手動的過程,程序員通常需要負(fù)責(zé)識別和實(shí)現(xiàn)并行化,而通常手動開發(fā)并行程序是一個耗時,復(fù)雜,易于出錯并且迭代的過程。很多年來,很多工具被開發(fā)出來,用以協(xié)助程序員將串行程序轉(zhuǎn)化為并行程序,而最常見的工具就是可以自動并行化串行程序的并行編譯器(parallelizing compiler)或者預(yù)處理器 (pre-processor)。
并行編譯器通常以如下兩種方式工作:
完全自動:
由編譯器分析源代碼并且識別可以并行化的部分,這里的分析包括識別出哪些部分滿足并行化的條件,以及權(quán)衡并行化是否真的可以提高性能。循環(huán)(包括do, for)通常是最容易被并行化的部分。
程序員指令:
通過采用“編譯器指令”或者編譯器標(biāo)識,程序員明確地告訴編譯器如何并行化代碼,而這可能會和某些自動化的并行過程結(jié)合起來使用。
最常見的由編譯器生成的并行化程序是通過使用結(jié)點(diǎn)內(nèi)部的共享內(nèi)存和線程實(shí)現(xiàn)的(例如OpenMP)。
如果你已經(jīng)有了串行的程序,并且有時間和預(yù)算方面的限制,那么自動并行化也許是一個好的選擇,但是有幾個重要的注意事項(xiàng):1)可能會產(chǎn)生錯誤的結(jié)果;2)性能實(shí)際上可能會降低;3)可能不如手動并行那么靈活;4)只局限于代碼的某個子集(通常是循環(huán));5)可能實(shí)際上無法真正并行化,由于編譯器發(fā)現(xiàn)里面有依賴或者代碼過于復(fù)雜。
接下來的部分僅適用于手動開發(fā)并行程序。
6.2 理解問題和程序
毫無疑問,開發(fā)并行程序的第一步就是理解你將要通過并行化來解決的問題。如果你是從一個已有的串行程序開始的,那么你需要首先理解這個串行程序。
在開始嘗試開發(fā)并行解決方案之前,需要確定該問題是否真正可以被并行化。
- 一個容易被并行化的問題如下。該問題容易被并行化,因?yàn)槊總€分子構(gòu)象都是獨(dú)立且確定的。計(jì)算最小能量構(gòu)象也是一個可以被并行化的問題。
計(jì)算數(shù)千個獨(dú)立分子構(gòu)象中每一個的勢能,完成之后,找出能量構(gòu)象最小的那一個。
- 一個不太可能被并行化的問題如下。由于F(n)同時依賴于F(n-1)和F(n-2),而后者需要提前被計(jì)算出來。
采用如下公式計(jì)算菲波那切數(shù)列 (0,1,1,2,3,5,8,13,21,…):F(n) = F(n-1) + F(n-2)。
識別程序的關(guān)鍵點(diǎn) (hotspots):
了解哪個部分完成了程序的大多數(shù)工作。大多數(shù)的科學(xué)和技術(shù)程序中,大多數(shù)的工作都是在某些小片段中完成的。可以通過剖析器或者性能分析工具來幫助你分析。專注于程序中這些關(guān)鍵點(diǎn),忽略那些占用少量CPU的其余部分。
識別程序中的瓶頸 (bottlenecks):
- 有沒有導(dǎo)致程序不成比例地變慢的,或者導(dǎo)致并行程序停止或者延遲的部分?例如有時候輸入輸出操作會導(dǎo)致程序變慢。
- 有時候也可能通過重構(gòu)程序,或者采用不同的算法來降低或者消除這些執(zhí)行很慢的區(qū)域。
識別并行化的抑制因素。一個常見的類型是數(shù)據(jù)依賴性 (data dependence),例如上面提到的菲波那切數(shù)列的例子。
如果可能的話,研究其它算法。這可能是設(shè)計(jì)并行程序的過程中最重要的一點(diǎn)。
利用成熟的第三方并行軟件,或者高度成熟的數(shù)學(xué)庫(例如IBM的ESSL,Intel的MKL,AMD的AMCL等)。
6.3 分割 (Partitioning)
設(shè)計(jì)并行程序的第一步就是將程序分解成為可以分配到不同任務(wù)中去的“塊”。這被稱為程序的分解 (decomposition) 或者分割 (partitioning)。通常有兩種基本方法可以將并行任務(wù)進(jìn)行分解:域分解和功能分解。
域分解: 在這種分割方式中,將數(shù)根據(jù)問題進(jìn)行分解。每個并行任務(wù)操作數(shù)據(jù)的一部分。
通常由不同的方式來對數(shù)據(jù)進(jìn)行分割:
功能分解:
在這種方法中,重點(diǎn)在于要執(zhí)行的計(jì)算,而不是計(jì)算所操縱的數(shù)據(jù)。問題根據(jù)要做的工作進(jìn)行分解,然后每個任務(wù)執(zhí)行整個工作的一部分。
這種功能分解非常適合于可分為不同任務(wù)的問題,例如:
生態(tài)系統(tǒng)建模:
每個程序計(jì)算給定組的人口,其中每個組的正常取決于其鄰居的增長。鎖著時間的推移,每個進(jìn)程計(jì)算當(dāng)前狀態(tài),然后與相鄰群體交換信息。然后所有任務(wù)進(jìn)行下一步計(jì)算。
信號處理:
音頻信號數(shù)據(jù)集通過四個不同的計(jì)算濾波器,每個濾波器是一個單獨(dú)的過程。第一段數(shù)據(jù)必須通過第一個濾波器,然后才能進(jìn)入第二個濾波器。當(dāng)這樣做時,第二段數(shù)據(jù)通過了第一個濾波器。當(dāng)?shù)谒膫€數(shù)據(jù)段處于第一個濾波器時(以及之后),四個任務(wù)都會變得很忙。
氣候建模:
每個模型組件都可以被認(rèn)為是一個單獨(dú)的任務(wù)。箭頭表示計(jì)算期間組件之間的數(shù)據(jù)交換:大氣模型需要使用風(fēng)速數(shù)據(jù)生成海洋模型;海洋模型使用海面溫度數(shù)據(jù)生成大氣模型等。
在實(shí)踐中將這兩種分解方式結(jié)合起來是很自然的,也是很常見的。
6.4 通訊 (Communications)
任務(wù)之間的通訊需求取決于你的問題:
不需要通訊的情況:
一些程序可以被分解成為并發(fā)執(zhí)行的任務(wù),而這些任務(wù)之間不需要共享數(shù)據(jù)。這類問題往往被稱為“尷尬并行”——任務(wù)之間不需要數(shù)據(jù)通訊。例如如果我們需要對下面一副圖片的顏色進(jìn)行取反(黑色的部分變?yōu)榘咨?,白色的變?yōu)楹谏模敲磮D像數(shù)據(jù)可以被簡單地分解為多個任務(wù),并且每個任務(wù)可以被獨(dú)立地執(zhí)行。
需要通訊的情況:
大多數(shù)并行程序并不像上一問題這么簡單,任務(wù)之間確實(shí)需要共享數(shù)據(jù)。例如下面這幅熱度擴(kuò)散圖需要一個任務(wù)知道其它任務(wù)在它的鄰居方格中的計(jì)算結(jié)果。鄰居數(shù)據(jù)的變化將直接影響到該任務(wù)的數(shù)據(jù)。
設(shè)計(jì)通訊需要考慮的因素: 在設(shè)計(jì)程序任務(wù)之間的通訊時,有大量的重要因素需要考慮:
通訊開銷:
1)任務(wù)間通訊幾乎總是意味著開銷。
2)而可以用于計(jì)算的機(jī)器周期以及資源會轉(zhuǎn)而用于對數(shù)據(jù)的封裝和傳輸。
3)頻繁的通訊也需要任務(wù)之間的同步,這有可能會導(dǎo)致任務(wù)花費(fèi)時間等待而不是執(zhí)行。
4)競爭通訊流量可能使可用的網(wǎng)絡(luò)帶寬飽和,從而進(jìn)一步加劇性能問題。
延遲 vs. 帶寬:
1)延遲 指的是從A點(diǎn)到B點(diǎn)發(fā)送最小量的信息所需要花費(fèi)的時間,通常以毫秒計(jì)。
2)帶寬 指的是單位時間內(nèi)可以傳輸?shù)臄?shù)據(jù)總量,通常以M/S或者G/S來計(jì)。
3)發(fā)送大量的短消息可能會導(dǎo)致延遲成為通訊的主要開銷。通常情況下將大量小信息封裝成為大消息會更加有效,從而提高通訊帶寬的利用效率。
通訊可見性:
1)在消息傳遞模型中,通訊往往是顯式和可見的,并且在編程者的控制之下。
2)在數(shù)據(jù)并行模型中,通訊對編程者來說往往是透明的,尤其是在分布式內(nèi)存架構(gòu)中。編程者往往甚至不能明確知道任務(wù)之間的通訊是如何完成的。
同步 vs. 異步通訊:
1) 同步通訊需要共享數(shù)據(jù)的任務(wù)之間某種意義上的“握手”。這既可以由編程者顯式地指定,也可以在底層被隱式地實(shí)現(xiàn)而不為編程者所知。
2)同步通訊業(yè)常常被稱為“阻塞通訊”,因?yàn)橐恍┤蝿?wù)必須等待直到它們和其它任務(wù)之間的通訊完成。
3)異步通訊允許任務(wù)之間獨(dú)立地傳輸數(shù)據(jù)。例如任務(wù)1可以準(zhǔn)備并且發(fā)送消息給任務(wù)2然后立即開始做其它工作,它并不關(guān)心任務(wù)2什么時候真正受到數(shù)據(jù)。
4)異步通訊也常常被稱為“非阻塞通訊”,因?yàn)樵谕ㄓ嵃l(fā)生的過程中,任務(wù)還可以完成其它工作。
5)在計(jì)算和通訊自由轉(zhuǎn)換是異步通訊的最大優(yōu)勢所在。
通訊的范圍:
明確哪些任務(wù)之間需要通訊在設(shè)計(jì)并行代碼的過程中是非常關(guān)鍵的。下面兩種通訊范圍既可以被設(shè)計(jì)為同步的,也可以被設(shè)計(jì)為異步的:
1)點(diǎn)對點(diǎn)通訊: 涉及到兩個任務(wù),其中一個扮演消息發(fā)送者/生產(chǎn)者的角色,另外一個扮演消息接受者/消費(fèi)者的角色。
2)廣播通訊: 涉及到多于兩個任務(wù)之間的數(shù)據(jù)共享。這些任務(wù)通常處于一個組或者集合中。
通訊的效率:
通常編程者具有影響通訊性能的選擇,這里列舉其中一些:1)對于一個給定的模型,究竟應(yīng)該采用哪一種實(shí)現(xiàn)?例如對于消息傳遞模型而言,一種MPI的實(shí)現(xiàn)可能在某個給定的硬件下比其它實(shí)現(xiàn)要快。2)什么采用什么類型的通訊操作?正如前面所提到的,異步通訊操作往往可以提高程序的整體性能。3)網(wǎng)絡(luò)結(jié)構(gòu)(network fabric):某些平臺可能會提供多于一個的網(wǎng)絡(luò)結(jié)構(gòu)。那么究竟哪一個最好?
開銷和復(fù)雜性:
最后需要意識到,上面提到的僅僅是需要注意的問題的一部分!
6.5 同步 (Synchronization)
管理工作的順序和執(zhí)行它的任務(wù)是大多數(shù)并行程序設(shè)計(jì)的關(guān)鍵,它也可能是提升程序性能的關(guān)鍵,通常也需要對某些程序進(jìn)行“串行化”。
同步的類型:
屏障:
1)這通常意味著會涉及到所有任務(wù);
2)每個任務(wù)都執(zhí)行自身的工作,直到它遇到屏障,然后它們就停止,或者“阻塞”;
3)當(dāng)最后一個任務(wù)到達(dá)屏障時,所有任務(wù)得以同步;
4)接下來可能發(fā)生的事情就有所變化了。通常會執(zhí)行一段串行代碼,或者所有的任務(wù)在這里都結(jié)束了。
鎖/信號量:
1)可以涉及任意多個任務(wù);
2)通常用于對全局?jǐn)?shù)據(jù)或者某段代碼的存取串行化(保護(hù)),在任一時刻,只有一個任務(wù)可以使用鎖/信號量;
3)第一個任務(wù)會獲得一個鎖,然后該任務(wù)就可以安全地對該保護(hù)數(shù)據(jù)進(jìn)行存??;
4)其它任務(wù)可以嘗試去獲得鎖,但必須等到當(dāng)前擁有該鎖的任務(wù)釋放鎖才行;
5)可以是阻塞的也可以是非阻塞的。
同步通訊操作:
1)僅僅涉及到執(zhí)行數(shù)據(jù)通訊操作的任務(wù);
2)當(dāng)一個任務(wù)執(zhí)行數(shù)據(jù)通訊操作時,通常需要在參與通訊的任務(wù)之間建立某種協(xié)調(diào)機(jī)制。例如,在一個任務(wù)發(fā)送消息時,它必須收到接受任務(wù)的確認(rèn),以明確當(dāng)前是可以發(fā)送消息的;
3)在消息通訊一節(jié)中也已經(jīng)說明。
6.6 數(shù)據(jù)依賴性 (Data Dependencies)
定義:
- 依賴: 當(dāng)語句的執(zhí)行順序影響程序的運(yùn)行結(jié)果時,我們稱程序語句之間存在依賴關(guān)系。
- 數(shù)據(jù)依賴: 數(shù)據(jù)依賴是由不同任務(wù)多次存取相同的內(nèi)存位置而產(chǎn)生的。
數(shù)據(jù)依賴也是并行程序設(shè)計(jì)中的關(guān)鍵,因?yàn)樗遣⑿谢幸粋€重要的抑制因素。
例子:
循環(huán)相關(guān)的數(shù)據(jù)依賴:下面這段代碼中,A(J-1)
必須在A(J)
之前被計(jì)算出來,因此說A(J)
與 A(J-1)
之間存在數(shù)據(jù)依賴,所以并行化在這里被抑制。如果任務(wù)2中有A(J)
,任務(wù)1中有A(J-1)
,那么要計(jì)算出正確的A(J)
則需要:1)分布式內(nèi)存架構(gòu):任務(wù)2必須在任務(wù)1計(jì)算結(jié)束之后,從任務(wù)1處中獲取A(J-1)
的值。2)共享內(nèi)存架構(gòu):任務(wù)2在任務(wù)1完成對A(J-1)
的更新之后,對A(J-1)
進(jìn)行讀取。
DO J = MYSTART,MYEND
A(J) = A(J-1) * 2.0
END DO
循環(huán)無關(guān)的數(shù)據(jù)依賴:在下面的例子中并行化也同樣被抑制。Y
的值依賴于:1)分布式內(nèi)存架構(gòu): 在任務(wù)之間是否需要或者何時需要對X
的值的通訊。2)共享內(nèi)存架構(gòu): 哪個任務(wù)最后存儲X
的值。
task 1 task 2
------ ------X = 2 X = 4
. .
. .
Y = X**2 Y = X**3
盡管在并行程序設(shè)計(jì)中,對所有數(shù)據(jù)依賴的識別都是重要的,但循環(huán)相關(guān)的數(shù)據(jù)依賴尤其重要,因?yàn)檠h(huán)往往是最常見的可并行化部分。
處理方法:
1)分布式內(nèi)存架構(gòu):在同步點(diǎn)傳輸所需數(shù)據(jù);
2)共享式內(nèi)存結(jié)構(gòu):在任務(wù)之間同步讀寫操作。
6.7 負(fù)載均衡 (Load Balancing)
負(fù)載均衡是指在任務(wù)之間分配大約相等數(shù)量的工作的做法,以便所有任務(wù)在所有時間保持繁忙,它也可以被認(rèn)為是使任務(wù)空閑時間最小化。出于性能原因方面的考慮,負(fù)載均衡對并行程序很重要。例如如果所有恩物都收到屏障同步點(diǎn)的影響,那么最慢的任務(wù)將決定整體性能。
如何實(shí)現(xiàn)負(fù)載均衡:
- 平均分配任務(wù)量:
對于數(shù)組/矩陣而言,如果每個任務(wù)都執(zhí)行相同或者類似的工作,那么在任務(wù)之間平均分配數(shù)據(jù)集;2)對于循環(huán)迭代而言,如果每個迭代完成的工作量大小類似,則在每個任務(wù)中分配相同或者類似的迭代次數(shù);3)如果你的架構(gòu)是由具有不同性能特征的機(jī)器異構(gòu)組合而成,那么請確保使用某種性能分析工具來簡則任何的負(fù)載不平衡,并相應(yīng)調(diào)整工作。
- 采用動態(tài)任務(wù)分配方法:
即使數(shù)據(jù)在任務(wù)之間被平均分配,但是某些特定類型的問題也會導(dǎo)致負(fù)載不平衡,如下面三個例子所示。
稀疏矩陣:某些任務(wù)會具有真實(shí)數(shù)據(jù),而大多數(shù)任務(wù)對應(yīng)的數(shù)據(jù)卻為0。
自適應(yīng)網(wǎng)格:某些方格需要被細(xì)分,而其它的不需要。
N體模擬:粒子可能會跨任務(wù)域遷移,因此某些任務(wù)會需要承擔(dān)更多的工作。
當(dāng)每個任務(wù)的工作量是可變的,或者無法預(yù)測的,那么可以采用 調(diào)度任務(wù)池 (Scheduler-task pool) 方法。每當(dāng)某個任務(wù)完成了它的工作,它就可以從工作隊(duì)列中領(lǐng)取新的任務(wù)。
最終來看,可能需要設(shè)計(jì)一種在代碼中動態(tài)發(fā)生和處理負(fù)載不平衡的算法。
6.8 粒度 (Granularity)
計(jì)算通訊比 (computation / Communication Ratio):
在并行計(jì)算中,粒度是對計(jì)算與通訊的比例的定性度量。計(jì)算周期通常通過同步時間與通訊周期分離。
細(xì)粒度并行化 (Fine-grain Parallelism):
1)在通訊事件之外進(jìn)行相對較少的計(jì)算工作;
2)計(jì)算通訊率較低;
3)方便負(fù)載均衡;
4)意味著較高的通訊開銷以及較少的性能提升機(jī)會;
5)如果粒度過細(xì),任務(wù)之間的通訊和同步的開銷可能需要比計(jì)算更長的時間。
粗粒度并行化 (Coarse-grain Parallelism):
1)在通訊/同步事件之外需要較大量的計(jì)算工作;
2)較高的計(jì)算/通訊比;
3)意味著較大的性能提升機(jī)會;
4)難以進(jìn)行較好的負(fù)載均衡。
最佳選擇:
最有效的粒度取決于具體算法及其所運(yùn)行的硬件環(huán)境。在大多數(shù)情況下,與通訊/同步相關(guān)的開銷相對于執(zhí)行速度很高,因此具有粗粒度的問題是相對有利的。而從另外一方面來講,細(xì)粒度則可以幫助減少由負(fù)載不均衡所造成的開銷。
6.9 輸入輸出 (I/O)
壞消息:
1)I/O操作通常被認(rèn)為是并行化的抑制劑;
2)I/O操作通常比內(nèi)存操作需要多個數(shù)量級的時間;
3)并行I/O系統(tǒng)可能不成熟或者不適用于所有平臺;
4)在所有任務(wù)均可以看到相同文件空間的環(huán)境中,寫操作可能導(dǎo)致文件被覆蓋;
5)讀操作可能受到文件服務(wù)器同時處理多個讀取請求的能力影響;
6)必須通過網(wǎng)絡(luò)進(jìn)行的I/O操作(NFS,非本地)可能導(dǎo)致嚴(yán)重的性能瓶頸,甚至導(dǎo)致文件服務(wù)器崩潰。
好消息:
已經(jīng)具有不少并行文件系統(tǒng),例如:
GPFS
:通用并行文件系統(tǒng) (General Parallel File System)(IBM),現(xiàn)在也被稱為IBM Spectrum Scale。
Lustre
:針對Linux的集群(Intel)。
HDFS
:Hadoop分布式文件系統(tǒng)(Apache)。
PanFS
:Panasas ActiveScale File System for Linux clusters (Panasas, Inc.)更多并行文件系統(tǒng)可以參加這里。
作為MPI-2的一部分,1996年以來MPI的并行I/O編程借口規(guī)范已經(jīng)可用。
注意事項(xiàng):
1)盡可能減少整體I/O操作;
2)如果你有權(quán)訪問并行文件系統(tǒng),請使用它;
3)在大塊數(shù)據(jù)上執(zhí)行少量寫操作往往比在小塊數(shù)據(jù)上進(jìn)行大量寫操作有著更明顯的效率提升;
4)較少的文件比許多小文件更好;
5)將I/O操作限制在作業(yè)的特定串行部分,然后使用并行通訊將數(shù)據(jù)分發(fā)到并行任務(wù)中。例如任務(wù)1可以讀輸入文件,然后將所需數(shù)據(jù)傳送到其它任務(wù)。同樣,任務(wù)2可以再從所有其它任務(wù)收到所需數(shù)據(jù)之后執(zhí)行寫入操作;
6)跨任務(wù)的I/O整合——相比于很多任務(wù)都執(zhí)行I/O操作,更好地策略是只讓一部分任務(wù)執(zhí)行I/O操作。
6.10 調(diào)試 (Debugging)
調(diào)試并行代碼可能非常困難,特別是隨著代碼量的擴(kuò)展。而好消息是有一些優(yōu)秀的調(diào)試器可以提供幫助:
1)Threaded - Pthreads和OpenMP;
2)MPI;
3)GPU/accelerator;
4)Hybrid。
在LC集群上也安裝有一些并行調(diào)試工具:
1)TotalView (RogueWave Software);
2)DDT (Allinea);
3)Inspector(Intel);
4)Stack Trace Analysis Tool(STAT)(本地開發(fā))。
更多的信息可以參考:LC web pages,TotalView tutorial。
6.11 性能分析和調(diào)優(yōu) (Performance Analysis and Tuning)
對于調(diào)試而言,并行程序的性能分析和調(diào)優(yōu)比串行程序更具挑戰(zhàn)性。幸運(yùn)的是,并行程序性能分析和調(diào)優(yōu)有很多優(yōu)秀的工具。Livemore計(jì)算機(jī)用戶可以訪問這種類似工具,其中大部分都在集群系統(tǒng)上。一些安裝在LC系統(tǒng)上的工具包括:
LC's web pages
:https://hpc.llnl.gov/software/development-environment-software
TAU
: http://www.cs.uoregon.edu/research/tau/docs.php
HPCToolkit
: http://hpctoolkit.org/documentation.html
Open|Speedshop
: http://www.openspeedshop.org/
Vampir / Vampirtrace
: http://vampir.eu/
Valgrind
: http://valgrind.org/
PAPI
: http://icl.cs.utk.edu/papi/
mpitrace
:https://computing.llnl.gov/tutorials/bgq/index.html#mpitrace
mpiP
: http://mpip.sourceforge.net/
memP
: http://memp.sourceforge.net/
7 并行示例
7.1 數(shù)組處理
此示例演示了對二維數(shù)組元素的操作:將某個函數(shù)作用于二維數(shù)組中的每個元素,其中對每個數(shù)組元素的操作都是獨(dú)立于其它數(shù)組元素的,并且該問題是計(jì)算密集型的。對于串行程序而言,我們依次對每個元素進(jìn)行操作,其代碼類似于:
do j = 1,n
do i = 1,n
a(i,j) = fcn(i,j)
end do
end do
問題:
- 該問題是否可以被并行化?
- 如果對該問題進(jìn)行分割?需要數(shù)據(jù)通訊嗎?
- 有沒有數(shù)據(jù)依賴?
- 有沒有同步需求?
- 是否需要考慮負(fù)載均衡?
并行方案1:
由于對元素的計(jì)算彼此之間是獨(dú)立的,所以可以有“尷尬并行”的解決方案。
由于數(shù)組元素是均勻分布的,所以每個進(jìn)程可以擁有陣列的一部分(子陣列)。
- 1)可以選擇最佳分配方案以實(shí)現(xiàn)高效的內(nèi)存訪問,例如選擇步幅為1,或者選擇合適的步幅以最大化緩存/內(nèi)存使用。
- 2)由于可以使單元跨越子陣列,所以分配方案的選擇也取決于編程語言,有關(guān)選項(xiàng)可以參見第 6.3 節(jié)。
由于數(shù)組元素的計(jì)算是彼此獨(dú)立的,所以不需要任務(wù)之間的通訊和同步。
由于任務(wù)之間的工作量是被平均分配的,所以不需要考慮負(fù)載均衡。
對數(shù)組分割之后,每個任務(wù)執(zhí)行與其擁有的數(shù)據(jù)相對應(yīng)的循環(huán)部分,其源代碼類似于:
請注意只有外部循環(huán)變量與串行解決方案不同。
for i (i = mystart; i < myend; i++) {
for j (j = 0; j < n; j++) {
a(i,j) = fcn(i,j);
}
}
一種可能的解決方案:
1)采用單程序多數(shù)據(jù) (SPMD) 模型進(jìn)行實(shí)現(xiàn),每個任務(wù)執(zhí)行相同的程序;
2)主進(jìn)程對數(shù)組進(jìn)行初始化,將信息發(fā)送給子任務(wù),并且接收計(jì)算結(jié)果;
3)子進(jìn)程接收到信息之后,執(zhí)行計(jì)算任務(wù),并且將結(jié)果發(fā)送給主進(jìn)程;
4)采用Fortran的存儲結(jié)構(gòu),對數(shù)組進(jìn)行塊劃分;
5)偽代碼如下所示。
6)具體的C代碼可以參見MPI Program in C:
find out if I am MASTER or WORKER if I am MASTER initialize the array send each WORKER info on part of array it owns send each WORKER its portion of initial array receive from each WORKER results else if I am WORKER receive from MASTER info on part of array I own receive from MASTER my portion of initial array # calculate my portion of array do j = my first column,my last column do i = 1,n a(i,j) = fcn(i,j) end do end do send MASTER results endif
并行方案2:
上一個并行方案展示了靜態(tài)負(fù)載均衡:1)每個任務(wù)執(zhí)行固定量的工作;2)某些很快或者負(fù)載較輕的處理器將會擁有空閑時間,而最慢執(zhí)行的任務(wù)最終決定整體性能。
如果所有任務(wù)在同一臺機(jī)器上運(yùn)行相同量的工作,那么靜態(tài)負(fù)載均衡往往并不是一個主要問題。但是如果你確實(shí)有負(fù)載均衡方面的問題(某些任務(wù)比其它任務(wù)運(yùn)行的快),那么你可以采用“任務(wù)池”(pool of tasks)模式。
任務(wù)池模式: 里面包含兩個進(jìn)程:
主進(jìn)程:
1)擁有任務(wù)池;2)如果得到請求,給工作進(jìn)程發(fā)送工作任務(wù);3)從工作進(jìn)程出收集返回結(jié)果。
工作進(jìn)程:
1)從主進(jìn)程處獲取任務(wù);2)執(zhí)行計(jì)算任務(wù);3)向主進(jìn)程發(fā)送結(jié)果。
工作進(jìn)程在運(yùn)行之前不知道它將處理數(shù)組的哪一部分,以及它將執(zhí)行多少任務(wù)。動態(tài)負(fù)載均衡發(fā)生在運(yùn)行時:運(yùn)行最快的任務(wù)將完成更多的任務(wù)。一段可能的源代碼如下:
find out if I am MASTER or WORKER if I am MASTER do until no more jobs if request send to WORKER next job else receive results from WORKER end do else if I am WORKER do until no more jobs request job from MASTER receive from MASTER next job calculate array element: a(i,j) = fcn(i,j) send results to MASTER end do endif
討論:
1)在上述任務(wù)池例子中,每個任務(wù)計(jì)算數(shù)組的某一個元素,計(jì)算與通訊比率是細(xì)粒度的;
2)細(xì)粒度的解決方案為了減少任務(wù)空閑時間,往往會導(dǎo)致更多的通訊開銷;
3)更好地解決方案可能是在每個任務(wù)中分配更多的工作,“正確”的工作量依然是依賴于具體問題的。
7.2 圓周率計(jì)算
該問題的串行代碼大約是這樣的:
npoints = 10000 circle_count = 0 do j = 1,npoints generate 2 random numbers between 0 and 1 xcoordinate = random1 ycoordinate = random2 if (xcoordinate, ycoordinate) inside circle then circle_count = circle_count + 1 end do PI = 4.0*circle_count/npoints
該問題是計(jì)算密集型的——大多數(shù)時間將花費(fèi)在對循環(huán)的執(zhí)行。
問題:
- 該問題是否可以被并行化?
- 如何對該問題進(jìn)行分割?
- 任務(wù)之間是否需要通訊?
- 是否存在數(shù)據(jù)依賴?
- 任務(wù)之間是否有同步需求?需
- 要考慮負(fù)載均衡嗎?
解決方案:
又一個容易被并行化的問題:
1)每個點(diǎn)的計(jì)算都是獨(dú)立的,不存在數(shù)據(jù)依賴;
2)工作可以被平均分配,不需要考慮負(fù)載均衡;
3)任務(wù)之間不需要通訊和同步。
下面是并行化之后的偽代碼:
npoints = 10000 circle_count = 0 p = number of tasks num = npoints/p find out if I am MASTER or WORKER do j = 1,num generate 2 random numbers between 0 and 1 xcoordinate = random1 ycoordinate = random2 if (xcoordinate, ycoordinate) inside circle then circle_count = circle_count + 1 end do if I am MASTER receive from WORKERS their circle_counts compute PI (use MASTER and WORKER calculations) else if I am WORKER send to MASTER circle_count endif
C語言的示例程序可以參考這里:MPI Program in C。
7.3 簡單熱方程
大多數(shù)并行計(jì)算問題需要任務(wù)之間的通訊,其中一大部分問題需要“相鄰”任務(wù)之間的通訊。
二維熱方程問題描述了在給定初始溫度分布以及邊界條件的情況下,溫度隨著時間的變化。有限差分方案可以采用數(shù)值方法求解正方形區(qū)域內(nèi)的熱擴(kuò)散方程:
二維數(shù)組的元素用來表示正方形區(qū)域內(nèi)的點(diǎn)的溫度;
邊界處的初始問題是0,中心點(diǎn)的問題最高;
邊界處的問題會保持為0;
采用時間步長算法。
每個元素的文圖的計(jì)算取決于它的鄰居的溫度:
串行程序的代碼可能使這個樣子:
do iy = 2, ny - 1 do ix = 2, nx - 1 u2(ix, iy) = u1(ix, iy) + cx * (u1(ix+1,iy) + u1(ix-1,iy) - 2.*u1(ix,iy)) + cy * (u1(ix,iy+1) + u1(ix,iy-1) - 2.*u1(ix,iy)) end do end do
問題:
該問題是否可以被并行化?
如何對該問題進(jìn)行分割?
任務(wù)之間是否需要通訊?
是否存在數(shù)據(jù)依賴?
任務(wù)之間是否需要同步?
是否需要考慮負(fù)載均衡?
解決方案:
該問題更具有挑戰(zhàn)性。因?yàn)榇嬖跀?shù)據(jù)依賴,所以需要任務(wù)之間的通訊和同步。整個數(shù)組需要被風(fēng)格成為子數(shù)組,并分配給不同任務(wù),每個任務(wù)擁有整個數(shù)組的一部分。由于任務(wù)量是均勻劃分的,所以不需要考慮負(fù)載均衡。
確定數(shù)據(jù)依賴:
1)一個任務(wù)的 內(nèi)部元素 和其它任務(wù)之間不存在數(shù)據(jù)依賴;
2)一個任務(wù)的 邊界元素 則和它的鄰居任務(wù)之間需要產(chǎn)生數(shù)據(jù)通訊。
采用單程序多數(shù)據(jù)模型(SPMD)進(jìn)行實(shí)現(xiàn):
1)主進(jìn)程向工作進(jìn)程發(fā)送初始信息,然后等待并收集來自工作進(jìn)程的計(jì)算結(jié)果;
2)工作進(jìn)程在特定的時間步長內(nèi)計(jì)算結(jié)果,并與鄰居進(jìn)程之間進(jìn)行數(shù)據(jù)交換。
偽代碼如下:
find out if I am MASTER or WORKER if I am MASTER initialize array send each WORKER starting info and subarray receive results from each WORKER else if I am WORKER receive from MASTER starting info and subarray # Perform time steps do t = 1, nsteps update time send neighbors my border info receive from neighbors their border info update my portion of solution array end do send MASTER results endif
示例程序可以參加:MPI Program in C。
7.4 一維波動方程
在這個例子中,我們計(jì)算經(jīng)過指定時間量之后,一維波動曲線的振幅。其中的計(jì)算會涉及到:
1)y軸上的振幅;
2)x軸上的位置索引i;
3)沿著波動曲線的節(jié)點(diǎn);
4)以離散時間步長更新振幅。
這里需要求解的是如下一維波動方程,其中c是常數(shù)。
A(i,t+1) = (2.0 * A(i,t)) - A(i,t-1) + (c * (A(i-1,t) - (2.0 * A(i,t)) + A(i+1,t)))
我們注意到,t時刻的振幅取決于前一刻的時間步長(t, t-1)以及相鄰點(diǎn)(i - 1, i + 1)。
問題:
該問題是否可以被并行化?
如何對該問題進(jìn)行分割?
任務(wù)之間是否需要通訊?
人物之間是否存在數(shù)據(jù)依賴?
任務(wù)之間是否需要同步?
是否需要考慮負(fù)載均衡?
解決方案:
這是涉及到數(shù)據(jù)依賴的另外一個例子,其并行方案將會涉及到任務(wù)見的通訊和同步。整個振幅陣列被分割并分配給所有的子任務(wù),每個任務(wù)擁有總陳列的相等的部分。由于所有點(diǎn)需要相等的工作,所以我們應(yīng)該均勻地分配節(jié)點(diǎn)。我們可以將工作分成多個塊,并且允許每個任務(wù)擁有大多數(shù)連續(xù)的數(shù)據(jù)點(diǎn)。而通訊只需要在數(shù)據(jù)邊界上進(jìn)行,塊大小越大,則所需的通信越少。
采用單程序多數(shù)據(jù)(SPMD)模型的實(shí)現(xiàn):
1)主進(jìn)程向工作進(jìn)程發(fā)送初始信息,并且等到各個工作進(jìn)程返回計(jì)算結(jié)果;
2)工作進(jìn)程對特定步長之內(nèi)的任務(wù)進(jìn)行計(jì)算,并且在必要的時候和鄰居進(jìn)程進(jìn)行數(shù)據(jù)通訊。
其偽代碼如下:
find out number of tasks and task identities #Identify left and right neighbors left_neighbor = mytaskid - 1 right_neighbor = mytaskid +1 if mytaskid = first then left_neigbor = last if mytaskid = last then right_neighbor = first find out if I am MASTER or WORKER if I am MASTER initialize array send each WORKER starting info and subarray else if I am WORKER` receive starting info and subarray from MASTER endif #Perform time steps #In this example the master participates in calculations do t = 1, nsteps send left endpoint to left neighbor receive left endpoint from right neighbor send right endpoint to right neighbor receive right endpoint from left neighbor #Update points along line do i = 1, npoints newval(i) = (2.0 * values(i)) - oldval(i) + (sqtau * (values(i-1) - (2.0 * values(i)) + values(i+1))) end do end do #Collect results and write to file if I am MASTER receive results from each WORKER write results to file else if I am WORKER send results to MASTER endif
程序示例可以參見:MPI Program in C。
8 參考文獻(xiàn)和更多信息
作者:Blaise Barney,Livermore Computing.
在萬維網(wǎng)上搜索“parallel programming”或者“parallel computing”將會獲得大量信息。
推薦閱讀:
”Designing and Building Parallel Programs”. Lan Foster.
http://www.mcs.anl.gov/~itf/dbpp/“
Introduction to Parallel Computing”. Ananth Grama, Anshul Gupta, George Karpis, Vpin Kumar.
http://www-users.cs.umn.edu/~karypis/parbook/“
Overview of Recent Supercomputers”. A.J. van der Steen, Jack Dongarra.
OverviewRecentSupercomputers.2008.pdf
圖片/圖像由作者以及其它LLNL成員創(chuàng)建,或者從不涉及版權(quán)的政府或公領(lǐng)域()獲取,或者經(jīng)所有者同意從其演示文稿或者網(wǎng)頁上獲取。
歷史:該材料有下面的資源演化而來,而這些資源將不再被維護(hù)或者不再可用。
Tutorials located in the Maui High Performance Computing Center's “SP Parallel Programming Workshop”.
Tutorials located at the Cornell Theory Center's “Education and Training” web page.
以上就是并行計(jì)算概念及定義全面詳解的詳細(xì)內(nèi)容,更多關(guān)于并行計(jì)算的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot + Vue + Electron 開發(fā) QQ 版聊天工具的詳細(xì)教程
這篇文章主要介紹了SpringBoot + Vue + Electron 開發(fā) QQ 版聊天工具的教程,本文通過截圖實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05JetBrains 學(xué)生認(rèn)證教程(Pycharm,IDEA… 等學(xué)生認(rèn)證教程)
這篇文章主要介紹了JetBrains 學(xué)生認(rèn)證教程(Pycharm,IDEA… 等學(xué)生認(rèn)證教程)文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09ISO-8859-1 、Latin-1 西歐編碼介紹及應(yīng)用
這篇文章主要介紹了ISO-8859-1 、Latin-1 西歐編碼介紹及應(yīng)用,需要的朋友可以參考下2016-06-06大數(shù)據(jù)HelloWorld-Flink實(shí)現(xiàn)WordCount
這篇文章主要介紹了大數(shù)據(jù)HelloWorld-Flink實(shí)現(xiàn)WordCount的相關(guān)知識,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-08-08Vscode的SSH插件遠(yuǎn)程連接Linux的實(shí)現(xiàn)步驟
本文主要介紹了Vscode的SSH插件遠(yuǎn)程連接Linux的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04輕量級思維導(dǎo)圖XMind?2023免費(fèi)激活教程
這篇文章主要介紹了輕量級思維導(dǎo)圖XMind?2023免費(fèi)激活教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07合成大西瓜開發(fā)源碼手把手教你運(yùn)行和部署大西瓜游戲項(xiàng)目(附源碼)
這篇文章主要介紹了合成大西瓜開發(fā)源碼手把手教你運(yùn)行和部署大西瓜游戲項(xiàng)目(附源碼),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02