一、背景知識
從1986年到2002年,微處理器的性能以平均50%的速度不斷提高。可是,從2002年開始,單處理器的性能提高速度降到每一年大約20%,這個差距是巨大的:若是以每一年50%的速度提高,在10年裏,微處理器的性能能提高60倍,而若是以20%的速度提高的話,10時間裏,只能提高6倍。因此,從2005年起,大部分主流的CPU製造商決定經過並行處理來快速提高微處理器的性能。他們再也不繼續開發速度更快的單處理器芯片,而是開始將多個完整的單處理器放到一個集成電路芯片上。這一變化對軟件人員帶來了重大的影響,也由此引出了一系列的問題:linux
爲何須要不斷提高的性能?
過去的幾十年,藉助不斷提高的計算能力,人類在許多領域(如:人類基因解碼、醫療成像、人工智能、虛擬現實等)發展的很是迅速。但隨着人類在科學步伐的前進,這裏領域的許多應用在計算能力上的要求也愈來愈高,解決問題的規模也在不斷的增長。編程
圖1 氣象模擬 圖2 蛋白質分析 圖3 藥物發現數組
爲何須要構建並行系統?
單處理器性能大幅度提高的主要緣由之一是日益增長的集成電路晶體管密度。隨着晶體管尺寸減少,傳遞速度增快,集成電路總體的速度也加快,它們的能耗也相應增長。大多數能量是以熱能的形式消耗,而在21世紀的前10年中,用空氣冷卻的集成電路的散熱能力已經達到極限了,因此,集成電腦製造商的決策是:與其構建更快、更復雜的單處理器,不如在芯片上放置多個相對簡單的處理器,這樣的有多個處理器的集成電腦稱之爲多核處理器。緩存
爲何須要編寫並行程序?
一般咱們傳統單核處理器上編寫的程序沒法利用多核處理器,咱們須要使得程序充分利用處理器更快的運行程序,更加及時與逼真的模擬現實世界。爲了達到這一目的,就須要軟件開發工程師將串行程序改寫爲並行程序。網絡
怎麼樣編寫並行程序?
普遍採用的兩種方式:任務並行和數據並行。框架
任務並行:是指將有待解決的問題須要執行的任務分配到各個核上完成。分佈式
數據並行:是指將有待解決的問題所須要處理的數據分配到各個核上完成,每一個核在所分配的大體至關的數據集上執行相同操做。函數
這裏咱們舉個例子來講明什麼是任務並行,什麼是數據並行?假如一個學校的高三總共有200個學生,有5個數學老師,分別是A、B、C、D、E老師,到期末考試的時候,數學試卷出了5道題目進行考試,在閱卷的時候,有兩種方案:每一個人負責一道題目進行打分;或者將學生分紅5組,每人負責一組,即20個學生。在這兩種方案中,數學老師充當計算機核的角色。oop
在第一種方案中,能夠認爲是任務並行的例子。有五個任務(題目)須要執行,即給批閱第一道題、批閱第二道題、……批閱第五道題。每一個人執行的指令是不相同的。應該每一道題的內容不一樣。性能
而第二種方案中,能夠認爲數據並行的例子,「數據」就是學生的試卷,在不一樣的核(打分人)之間平分,每一個核執行大體相同的指令。
二、並行硬件
咱們目前的計算機都是基於經典的馮偌伊曼結構的:主存+CPU+總線(互連設備)。根據Flynn(費林)分類法,即基於指令和數據流方式,能夠將並行計算機劃分爲:SISD、MISD、SIMD和MIMD四種。具體以下圖:
圖4 硬件系統
通俗的講,SISD系統便是咱們典型的馮諾依曼系統,它是一次執行一條指令,一次存取一個數據項。而其它三個纔是真正的並行計算系統。SIMD系統經過對多個數據執行相同的指令,從而實如今多個數據流上的操做,所以,該系統很是適合處理大型數組的簡單循環,今後衍生出向量處理器,重點對數組或數據向量進行操做。這裏重點說明一下,咱們常說的GPU(graphics processing unit)圖形處理器計算機就是講物體表面的內部表示爲使用點、線、面的像素數組來表示的,也是一個概念上的SIMD系統,不過隨着技術的發展,現代的GPU也能夠有幾十個核,每一個核也能獨立的執行指令流。
在並行計算中,通常將MIMD做爲主要研究對象。其中MIMD系統主要有兩種類型:共享內存系統(圖5)和分佈式內存系統(圖6)。
圖5 共享內存系統 圖6 分佈式內存系統
在共享內存系統中,自治的CPU經過互連網絡與內存系統相連,每一個CPU都能訪問每一個內存系統中的內存。分佈式內存系統中,每一個CPU都有本身的獨立內存,每一個單元之間的內存訪問經過消息通信或者特殊的函數來進行。
三、並行軟件
SPMD(單程序多數據流):指的不是在每一個核上運行不一樣的程序,而是一個程序僅包含一份代碼,經過必定的條件分支,使得這一份代碼再執行的時候表現的像是在不一樣的處理器上執行不一樣的代碼。
在咱們主要討論的MIMD分佈式內存系統中,各個核可以直接訪問本身的內存,而運行在不一樣核之間的進程須要交換內存數據的時候,只能經過消息傳遞API來實現。消息傳遞的API至少要提供一個發送函數和接收函數。進程之間經過它們的序號(rank)進行識別。
咱們編寫並行計算程序的主要目的固然是爲了提供它們的性能,那麼咱們應該如何去評價一個並行計算程序的性能呢?答案是:加速比與效率。
加速比:
效率:
理論上而言,若是使用p個進程或者線程來運行一個並行程序,而且每一個核中之多隻有一個進程/線程,那麼,S=p,E=1。可是在實際狀況下,S<p,E<1。既然已經知道如何評價一個將串行程序改成並行程序的性能,那麼如今假設咱們已經有了一個串行程序,爲了提升性能,咱們如何將串行程序改成高性能的並行計算程序呢?須要哪些步驟?
通常狀況下,須要將工做進行拆分,使得分佈在每一個進程中的工做量大體相仿,並行讓它們之間的通訊量最少。因而串行程序並行化設計步驟通常按如下幾步進行:
第一步:劃分。將串行程序中須要要執行的指令和數據按照計算部分拆分紅多個小任務。關鍵:識別出能夠進行並行執行的任務。
第二步:通信。肯定第一步識別出來的任務之間須要執行那些通訊。
第三步:凝聚/聚合。將第一步肯定的任務與通訊結合成更大的任務。
第四步:分配。將上一步聚合好的任務分配到進程/線程中。這一步還主要注意的是,要使得通訊量最小化,讓各個進程/線程所獲得的工做量大體均衡。
四、實現的手段
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,這兩個標準分別用於三維圖形和計算機音頻方面。
GPU是專門爲執行復雜的數學和集合計算而設計的,一個GPU內有許多流處理簇(stream Multiprocessor)SM,他們就相似於CPU的核。這些SM與共享(一級緩存)鏈接在一塊兒,而後又與至關於SM間互聯開關的二級緩存相連。相似於這種設計,都是爲計算圖形渲染所必須的。
是谷歌公司MapReduce框架的一個開源版本。它針對的是linux平臺。其概念是你取來一個大數據集,而後將其切割或映射(map)成不少小的數據塊。然而,並非將數據發送到各個節點,取而代之的是數據集經過並行文件系統已經被劃分給上百或者上千個節點。所以,歸約(Reduce)步驟就是把程序發送到已經包含數據的節點上,而後輸出結果寫入本地節點並保存在那裏。