在過去一段長(zhǎng)時(shí)間里,x86系統(tǒng)上軟件的性能隨著來自Intel和AMD處理器速度越來越快而不斷提高,開發(fā)者只需對(duì)現(xiàn)有軟件程序作輕微改動(dòng)就能坐觀其性能在隨著硬件性能的上升而不斷提升。不過,多核設(shè)計(jì)概念的出現(xiàn)迫使軟件世界不得不直面并行性(將單個(gè)任務(wù)拆分成多個(gè)小塊以便分別處理之后再重新組合的能力)問題。當(dāng)然,為服務(wù)器設(shè)計(jì)軟件的開發(fā)者已經(jīng)解決了一些此類難題,因?yàn)槎嗪颂幚砥骱投嗦废到y(tǒng)在服務(wù)器市場(chǎng)已經(jīng)存在多年(在傳統(tǒng)的Unix領(lǐng)域),一些運(yùn)行在RISC架構(gòu)多核多路系統(tǒng)上的應(yīng)用程序已經(jīng)被設(shè)計(jì)成多線程以利用系統(tǒng)的并行處理能力。但是,在x86領(lǐng)域,應(yīng)用程序開發(fā)者多年來一直停留在單線程世界,生產(chǎn)所謂的“順序軟件”。
  
    現(xiàn)在的情況是軟件開發(fā)者必須找出新的開發(fā)軟件的方法,面向?qū)ο缶幊痰呐d起增加了匯編語言的復(fù)雜性,并行編程也需要新的抽象層次。另一方面,處理器設(shè)計(jì)廠商在設(shè)計(jì)產(chǎn)品時(shí)也應(yīng)該將軟件開發(fā)者考慮在內(nèi),“處理器的首要著眼點(diǎn)應(yīng)該是可編程性,而不是速度。”Sutter說。多核處理器要想發(fā)揮出威力,關(guān)鍵在于并行化軟件支持,多核設(shè)計(jì)帶動(dòng)并行化計(jì)算的推進(jìn),而給軟件帶來的影響更是革命性的。
  
    Intel很早就通過超線程技術(shù)實(shí)現(xiàn)了邏輯上的雙處理器系統(tǒng),可以并行計(jì)算,但這不過是對(duì)處理器閑置資源的一種充分利用而已,并且這種充分利用只有在特定的條件下,尤其是針對(duì)流水線比較長(zhǎng)且兩種運(yùn)算并不相互交叉的時(shí)候,才會(huì)有較高的效率,如編碼解碼、長(zhǎng)期重復(fù)某種矩陣運(yùn)算以及一些沒有經(jīng)過仔細(xì)編寫的軟件等。
  
    即使IBM的Power5架構(gòu),也需要跟最新的操作系統(tǒng)進(jìn)行融合,加上運(yùn)行在其上的軟件,才有可能利用并發(fā)多線程。虛擬化技術(shù)在一定程度上能夠處理一些因?yàn)槎嗪藥淼膯栴},可以讓應(yīng)用軟件和操作系統(tǒng)在透明的環(huán)境下對(duì)處理器資源進(jìn)行分配和管理。
  
    目前在對(duì)稱多處理器方面,操作系統(tǒng)對(duì)資源的分配和管理并沒有本質(zhì)的改變,多以對(duì)稱的方式進(jìn)行平均分配。也就是說,在操作系統(tǒng)層面,當(dāng)一個(gè)任務(wù)到來時(shí),剝離成為兩個(gè)并行的線程,因?yàn)榫€程之間需要交流以及操作系統(tǒng)監(jiān)管,它導(dǎo)致的效率損失要比硬件層面大得多。并且,多數(shù)軟件并沒有充分考慮到雙核乃至多核的運(yùn)行情況,導(dǎo)致線程的平均分配時(shí)間以及線程之間的溝通時(shí)間都會(huì)大大增加,尤其是當(dāng)線程需要反復(fù)訪問內(nèi)存的時(shí)候。目前,多數(shù)操作系統(tǒng)還沒有完全實(shí)現(xiàn)自由的資源分配,如IBM是通過AIX 5.3L來支持Power5上的虛擬化功能,才實(shí)現(xiàn)了資源的動(dòng)態(tài)調(diào)配和劃分的。
  
    從長(zhǎng)遠(yuǎn)來看,需要使用虛擬化技術(shù)才可能實(shí)現(xiàn)操作系統(tǒng)對(duì)任務(wù)的具體劃分,這很可能改變一些通用的編程模式。
  
    面對(duì)多核系統(tǒng),需要有并行編程的思想才有可能充分利用資源,而人類的思維模型習(xí)慣于線性思維,對(duì)“面”或者更為復(fù)雜的立體編程模式,效率會(huì)下降很多。軟件在并行化方面的滯后給多核處理器技術(shù)的發(fā)展蒙上了一些陰影。盡管用戶在充滿希望地期待著,但思維的改變不是一朝一夕的事情。服務(wù)器端的并行化應(yīng)用設(shè)計(jì)似乎已經(jīng)解決了一些,但仍需要努力提高其擴(kuò)展能力。
  
    并行化對(duì)于客戶端的應(yīng)用是一項(xiàng)巨大的挑戰(zhàn),而對(duì)于許多基于服務(wù)器的程序來說,卻是一個(gè)“已經(jīng)圓滿解決的問題”。我們?cè)诜?wù)器上使用的并行化架構(gòu)一直在很好地工作,但要想確保這類架構(gòu)的順利編程和擴(kuò)展能力,人們?nèi)匀恍枰冻鼍薮蟮呐?。這些應(yīng)用通常都具有很強(qiáng)的并行特性,它們可以同時(shí)處理許多獨(dú)立的請(qǐng)求流。例如,一臺(tái)Web服務(wù)器或一個(gè)Web站點(diǎn)可以獨(dú)立執(zhí)行同一代碼在大部分不重疊數(shù)據(jù)上的數(shù)千個(gè)版本。此外,這些執(zhí)行都是相互獨(dú)立的,通過一個(gè)抽象數(shù)據(jù)存儲(chǔ)來共享狀態(tài),例如通過支持高度并行化訪問結(jié)構(gòu)化數(shù)據(jù)庫。今天,表達(dá)并行的方式有很多種,每種方式只適用于一個(gè)特定的程序子集。這些并行編程模型在兩方面的區(qū)別比較大:并行運(yùn)行的粒度和任務(wù)間相互配合的程度。
  
    并行執(zhí)行的操作可能是單個(gè)指令,如加法或乘法,也可能是需要用幾天時(shí)間來運(yùn)行的復(fù)雜程序。很明顯,對(duì)于小型操作來說,并行基礎(chǔ)設(shè)施的開銷成本是非常巨大的,總的來說,任務(wù)分割得越小,將其生成為單個(gè)任務(wù)和提供通信及同步時(shí)所需要的成本就越高。
  
    另外一個(gè)方面就是操作間通信和同步配合的程度。最理想的程序是沒有任何的配合,操作完全是獨(dú)立運(yùn)行的,而且產(chǎn)生的結(jié)果也是完全不同的。在這種情況下,操作可以按任何順序運(yùn)行,也不會(huì)產(chǎn)生任何同步或通信成本,在編程時(shí)無須考慮數(shù)據(jù)競(jìng)爭(zhēng)的問題,編程過程自然也就會(huì)非常容易。然而,這種狀態(tài)是非常罕見的,多數(shù)并行程序都要在操作之間共享數(shù)據(jù)。當(dāng)操作變得越來越多樣化時(shí),確保正確和有效的操作其復(fù)雜性也會(huì)隨之提高。最簡(jiǎn)單的案例是為每個(gè)操作執(zhí)行相同的代碼,這種共享類型是一種無規(guī)律的并行方式。更具有挑戰(zhàn)性的是,無規(guī)劃的并行方式,在這種方式中,操作是完全不同的,而且共享方式也更難以理解。
  
    獨(dú)立并行 在這種方式下,一種或多種操作是針對(duì)數(shù)據(jù)集中的每個(gè)項(xiàng)目獨(dú)立實(shí)施執(zhí)行的。精細(xì)的數(shù)據(jù)并行依靠的是操作的并行執(zhí)行,它們不應(yīng)當(dāng)共享輸入的數(shù)據(jù)或結(jié)果,并應(yīng)當(dāng)在無協(xié)調(diào)的情況下完全可以執(zhí)行。
  
    在實(shí)際應(yīng)用中,搜索引擎等應(yīng)用只共享一個(gè)大型的只讀數(shù)據(jù)庫,因此并發(fā)的處理檢索不需要任何協(xié)調(diào),同樣,大型模擬通常需要在運(yùn)行時(shí)分析大量的輸入?yún)?shù),也是一種獨(dú)立并行模型。
  
    有規(guī)律的并行比獨(dú)立并行更復(fù)雜一些的是當(dāng)運(yùn)算之間存在相互依存關(guān)系時(shí),將同一種運(yùn)算應(yīng)用到一個(gè)數(shù)據(jù)集上。如果兩個(gè)運(yùn)算之間存在通信或同步,則在數(shù)據(jù)上某一部分執(zhí)行的運(yùn)算會(huì)與另外一個(gè)運(yùn)算存在依存關(guān)系。有規(guī)律的并行程序要想取得正確的結(jié)果,需要同步或認(rèn)真協(xié)調(diào)執(zhí)行策略,與一般并行不同的是,我們可以對(duì)這類操作背后的代碼進(jìn)行分析,確定如何以并發(fā)的方式對(duì)其加以執(zhí)行,以及確定它們共享哪些數(shù)據(jù)。
  
    無結(jié)構(gòu)的并行acerun: yes”> 無結(jié)構(gòu)的并行對(duì)數(shù)據(jù)的訪問是不可預(yù)見的,而且需要通過明確的同步方式對(duì)其加以協(xié)調(diào)。在使用線程和明確的同步方式寫成的程序中,這種并行形式最為普遍。在這類程序中每一個(gè)線程都有自己特定的職責(zé),我們很難討論這類并行形式中任何具體的內(nèi)容,但有一點(diǎn):兩個(gè)線程在訪問數(shù)據(jù)時(shí)如果發(fā)生沖突,就必須使用明確的同步方式來解決,否則,程序?qū)⑦M(jìn)入無法確定的狀態(tài)。
  
    實(shí)現(xiàn)軟件并行化,需要更好的編程語言,需要更高層的語言抽象,使現(xiàn)有的應(yīng)用能夠以一種漸進(jìn)的方式轉(zhuǎn)變成并行化的應(yīng)用。
  
    在編程語言中我們需要什么?需要更高層的語言抽象,包括現(xiàn)有命令式語言的發(fā)展性擴(kuò)充,使現(xiàn)有的應(yīng)用能夠以一種漸進(jìn)的方式轉(zhuǎn)變成并行化應(yīng)用。這種編程模型必須將并行化轉(zhuǎn)變成一種易于理解和分析的形式,而且不僅是在最初的開發(fā)階段,在維護(hù)階段更是如此。明示、暗示和自動(dòng)并行 明示的編程模型可以提供抽象的方法,并要求編程人員能夠明確地說明并行在哪里發(fā)生。明顯表達(dá)并行的主要優(yōu)勢(shì)在于,它允許編程人員充分利用應(yīng)用領(lǐng)域的知識(shí),并充分表達(dá)應(yīng)用中潛在的并行性。 
  
    然而,它要求新的、更高一層的編程抽象,并且在處理共享數(shù)據(jù)時(shí)需要更高層次的編程能力。暗示的編程模型將并行性隱藏在庫中或API(應(yīng)用程序接口)后面,因此調(diào)用方看到的仍然是順序的形式,而由庫去執(zhí)行并行操作。它的主要缺點(diǎn)是,這種方法不可能實(shí)現(xiàn)某些與并行有關(guān)的性能提高。此外,這種方式也很難設(shè)計(jì)出一種在任何情況下都不顯示并行性的界面。
  
    人們還在廣泛研究另外一種方法,這就是自動(dòng)并行處理。在這種方法中,編譯器將負(fù)責(zé)查找并行,通常是在那些以Fortran等傳統(tǒng)語言寫成的程序中。這種方法從表面上來看非常具有吸引力,但在實(shí)踐中并不能很好地工作。要想理解程序的潛在行為,精確的程序分析是必不可少的。即使是對(duì)于Fortran 這種簡(jiǎn)單的語言來說,這種分析也是非常具有挑戰(zhàn)性的。此外,順序程序通常都使用順序算法,其中包含的并發(fā)特性極少。
  
    命令式和功能式語言 常用的商業(yè)編程語言(如Pascal、C、C++、Java、C#)都屬于命令式的語言,即由編程人員規(guī)定變量和數(shù)據(jù)結(jié)構(gòu)中的變化。函數(shù)(如循環(huán))、低級(jí)數(shù)據(jù)操作和共享式的可變對(duì)象實(shí)例都會(huì)使這些語言編寫而成的程序很難分析和自動(dòng)并行執(zhí)行。一般人都相信,功能語言,如 Scheme、ML或Haskell可以消除這種困難,因?yàn)樗鼈兲焐瓦m合并行運(yùn)行,用這些語言編寫的程序可以操縱不可變的對(duì)象實(shí)例,而在實(shí)踐中,功能語言并不一定能夠給并行執(zhí)行帶來益處。功能程序中的并行通常是在過程調(diào)用層面上的,而且為了適應(yīng)傳統(tǒng)的多處理器,這些過程被分割成了粒度非常精細(xì)的程序,幾乎達(dá)到了不切實(shí)際的地步。功能語言對(duì)并行處理的真正貢獻(xiàn)在于,這些語言通常使用的都是更高層次的編程風(fēng)格,而在這種風(fēng)格中,Map和Map-reduce 等操作會(huì)將計(jì)算應(yīng)用于集合數(shù)據(jù)結(jié)構(gòu)的所有組件,這些較高層次的運(yùn)算都是并行執(zhí)行的資源。例如,Google的高級(jí)工程師就曾經(jīng)描述過Google是如何使用Map-Reduce來進(jìn)行大規(guī)模分布式計(jì)算的。命令式語言可以將功能擴(kuò)展添加進(jìn)來,這一點(diǎn)非常重要,為了保留目前的各類軟件中的巨大投資,用戶自然希望以漸進(jìn)的方式逐步添加對(duì)并行處理的支持。
  
    更好的抽象今天的多數(shù)語言提供的是線程和鎖定層面上的明示編程方式,這些抽象都屬于低層次的。較高層次的抽象允許編程人員表達(dá)那些具備固有并行特性的任務(wù),而運(yùn)行時(shí)系統(tǒng)就可以對(duì)其進(jìn)行組合和調(diào)度,使其適合實(shí)際機(jī)器上的硬件,這樣就可以使應(yīng)用能夠在比較新的硬件上發(fā)揮更好的性能。
  
    高層次抽象的另外一個(gè)例子就是活動(dòng)對(duì)象?;顒?dòng)對(duì)象在概念上運(yùn)行在自己的線程上,因此創(chuàng)建1000個(gè)此類對(duì)象就相當(dāng)于從概念上創(chuàng)造1000個(gè)潛在的執(zhí)行線程?;顒?dòng)對(duì)象的行為方式與監(jiān)視器非常像,但它不需要傳統(tǒng)的鎖定。相反,活動(dòng)對(duì)象以外的方法調(diào)用都是異步信息,由對(duì)象對(duì)其進(jìn)行匯集、排隊(duì)和傳送。
  
    開發(fā)人員已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了一些有趣的編程模型,有助于開發(fā)并行應(yīng)用程序,最流行的就是用于共享內(nèi)存編程的OpenMP和用于分布式內(nèi)存編程的MPI。



  
    OpenMP程序示例
  
    OpenMP是一種工業(yè)標(biāo)準(zhǔn)的API設(shè)計(jì)規(guī)范,是由Sun、HP、IBM和Intel等多家頂級(jí)計(jì)算機(jī)廠商和軟件開發(fā)商聯(lián)手推出的,其目的在于為軟件開發(fā)人員提供一種通用的規(guī)范,使其可以很方便地設(shè)計(jì)新并行應(yīng)用程序或修改及并行化現(xiàn)有串行應(yīng)用程序,從而利用配置了多處理器計(jì)算系統(tǒng)的共享內(nèi)存。可移植性也是OpenMP的主要目標(biāo)之一,使用OpenMP開發(fā)的并行應(yīng)用程序源代碼可由支持OpenMP的任何編譯器編譯,且編譯好的二進(jìn)制代碼可在目標(biāo)硬件平臺(tái)上運(yùn)行,以獲得出色的并行性能。
  
     最流行的本地編程語言Fortran和C/C++都支持OpenMP。左圖給出了分別以C/C++和Fortran編寫的簡(jiǎn)單OpenMP程序示例。在本例中,將y數(shù)組加到x數(shù)組這一循環(huán)迭代操作,是以并行方式執(zhí)行的。源代碼中的編譯指示、指令和編程API調(diào)用表示了OpenMP的結(jié)構(gòu)。 OpenMP 的結(jié)構(gòu)允許程序員指定并行區(qū)域、同步和數(shù)據(jù)作用域?qū)傩?,它還支持用于指定運(yùn)行時(shí)配置的環(huán)境變量,例如,環(huán)境變量OMP_NUM_THREADS指定了運(yùn)行時(shí)所使用的工作線程的數(shù)量。
  
    由于OpenMP編程模型專用于單一進(jìn)程,因此其可伸縮性最終要受到一臺(tái)計(jì)算機(jī)中處理器(線程)數(shù)量的限制??缮炜s性還會(huì)受編程邏輯復(fù)雜程度和編程風(fēng)格的限制。當(dāng)前的OpenMP語義尚不夠靈活,無法處理某些應(yīng)用程序。例如,當(dāng)前的OpenMP規(guī)范僅允許在并行區(qū)域內(nèi)創(chuàng)建有限的動(dòng)態(tài)線程。
  
    MPI(Message Passing Interface,消息傳遞接口)是一種工業(yè)標(biāo)準(zhǔn)的API規(guī)范,專為在多處理器計(jì)算機(jī)和計(jì)算機(jī)集群上獲得高性能計(jì)算而設(shè)計(jì),該標(biāo)準(zhǔn)是由大量計(jì)算機(jī)供應(yīng)商和軟件開發(fā)商共同設(shè)計(jì)的。有多種來自不同研究機(jī)構(gòu)和廠商的MPI實(shí)現(xiàn),其中最流行的一種就是MPICH,MPICH常用作為特定平臺(tái)或互連而優(yōu)化的MPI 實(shí)現(xiàn)的編碼基礎(chǔ)。MPI實(shí)現(xiàn)依然在不斷發(fā)展。MPI-1支持一些關(guān)鍵特性,如點(diǎn)到點(diǎn)及與通信設(shè)備的集群消息通信。一條消息中可包含基本數(shù)據(jù)類型或派生(用戶定義的)數(shù)據(jù)類型的MPI數(shù)據(jù),它還支持互連拓?fù)洹PI-2則提供許多高級(jí)通信特性,如遠(yuǎn)程內(nèi)存訪問和單端通信等,還支持動(dòng)態(tài)進(jìn)程創(chuàng)建、管理和并行 I/O。
  
    總體而言,MPI為計(jì)算機(jī)集群上的并行應(yīng)用程序提供了一個(gè)出色的解決方案,但對(duì)于許多開發(fā)人員來說,MPI也是一種困難的編程模型,因?yàn)镸PI 的通信延遲時(shí)間較長(zhǎng),所以必須合理分割程序的核心邏輯,以使分布成本更為合理。分析及劃分應(yīng)用程序問題,并將問題映射到分布式進(jìn)程集合中,絕對(duì)不是一項(xiàng)可靠直覺完成的任務(wù),因?yàn)樵S多MPI進(jìn)程之間的交互作用都相當(dāng)復(fù)雜,因此即便選用了恰當(dāng)?shù)墓ぞ?,調(diào)試并調(diào)整運(yùn)行在大量節(jié)點(diǎn)上的MPI應(yīng)用程序也極具挑戰(zhàn)性。 MPI的性能取決于底層硬件平臺(tái)和互連,在某些極端的情況下,MPI應(yīng)用程序的性能可能會(huì)受到繁重的互連流量的影響。另外一個(gè)嚴(yán)重的問題就是大規(guī)模MPI 應(yīng)用程序的可靠性。對(duì)于許多MPI實(shí)現(xiàn)而言,只要單一計(jì)算節(jié)點(diǎn)發(fā)生故障,無法正確響應(yīng),MPI程序就會(huì)停止工作。(本文內(nèi)容由Sun軟件架構(gòu)師 Liang T?Chen和微軟軟件架構(gòu)師Herb Sutter提供)
  
    在服務(wù)器端,RISC架構(gòu)的服務(wù)器進(jìn)入多核技術(shù)領(lǐng)域要早一些,所以一些專有的、或者說是基于Unix操作系統(tǒng)的行業(yè)化特征非常顯著的應(yīng)用已經(jīng)是并行化編寫的。而當(dāng)x86領(lǐng)域迎來64位計(jì)算和多核技術(shù)的時(shí)候,絕大多數(shù)的基于Windows的應(yīng)用都是傳統(tǒng)的按照單一線程開發(fā)的。
  
    現(xiàn)在,標(biāo)準(zhǔn)化、開放、TCO等浪潮席卷整個(gè)計(jì)算領(lǐng)域,x86服務(wù)器市場(chǎng)在飛速發(fā)展,逐步擠壓原來的、非常強(qiáng)勢(shì)的RISC架構(gòu)服務(wù)器占有的份額,跟隨服務(wù)器硬件技術(shù)的發(fā)展腳步,基于x86服務(wù)器的操作系統(tǒng)以及上層應(yīng)用,都需要考慮處理器級(jí)別的多核、并行計(jì)算設(shè)計(jì)帶來的性能提升,考慮軟件如何能夠適應(yīng)并且更充分發(fā)揮硬件架構(gòu)的優(yōu)勢(shì)。應(yīng)該說,這是軟件層進(jìn)入了大規(guī)模的并行化設(shè)計(jì)階段,畢竟,在銷售量方面,x86市場(chǎng)是絕對(duì)領(lǐng)先的。
  
    記者之前接觸過一些將應(yīng)用改為并行運(yùn)行的案例,是采用集群系統(tǒng)后,將原來的應(yīng)用進(jìn)行一些修改以便能夠充分利用集群系統(tǒng)并行處理的優(yōu)勢(shì),比如石油勘探行業(yè)的用戶,他們?cè)谟?jì)算和分析地震勘探資料應(yīng)用中,采用大規(guī)模并行計(jì)算系統(tǒng)來實(shí)現(xiàn)疊前偏移和精確地震成像處理,提高勘探開發(fā)效益。不過,這些應(yīng)用都還處在一個(gè)剛剛開始的并行化應(yīng)用階段,采用的是集群系統(tǒng)。多核技術(shù)在x86服務(wù)器中成熟后,如何能夠充分利用到多核并行處理的優(yōu)勢(shì),才是軟件層面真正的挑戰(zhàn),就是所謂的“線程級(jí)并行”。
  
    處理器在并行計(jì)算方面所做出的技術(shù)革新貢獻(xiàn),僅僅是整個(gè)產(chǎn)業(yè)鏈上的一個(gè)小環(huán)節(jié),與用戶應(yīng)用緊密相連的是軟件層,正如文章中引述的微軟軟件架構(gòu)師Sutter所說的:處理器設(shè)計(jì)首要的著眼點(diǎn)應(yīng)該是可編程性,而不是速度。

分享到

多易

相關(guān)推薦