• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-9  評論-6  文章-0  trackbacks-0

             

            [轉(zhuǎn)自程序員]

            深遠(yuǎn)影響

              在過去30年里,并發(fā)雖然一直被鼓吹為“下一件大事”或“未來之路”,但軟件界不為所動。現(xiàn)在,并行終于出現(xiàn)在我們面前了:新一代計算機全面支持并發(fā),這將引發(fā)軟件開發(fā)方式的巨變。

              本文主要討論并發(fā)對軟件——包括編程語言和程序員——的深遠(yuǎn)影響。

              Olukotun和Hammond所描述的硬件發(fā)展,代表著計算機計算方式的重大變化。過去30年里,半導(dǎo)體工業(yè)的發(fā)展及其在處理器上的應(yīng)用,推動了已有順序式軟件運行速度的穩(wěn)步提升。但體系結(jié)構(gòu)上的多核處理器變化僅對并發(fā)應(yīng)用有益,因此幾乎對絕大多數(shù)現(xiàn)存軟件沒有價值。在不久的將來,已有的桌面應(yīng)用不可能比現(xiàn)在跑得更快。實際上,它們的運行速度會稍慢,因為為了降低高密度多核處理器的電能消耗,新的芯片內(nèi)核被簡化并運行在更低的時鐘速度。

              這將對軟件至少是主流軟件的開發(fā)帶來深遠(yuǎn)影響。計算機的能力無疑越來越強,但程序不再可能從硬件性能提升大餐中免費獲益,除非它們實現(xiàn)了并發(fā)。

              即便拋開多核變化的強制要求不談,我們也有理由實現(xiàn)并發(fā),尤其是將工作從同步轉(zhuǎn)到異步,可以提高響應(yīng)速度,就像目前的應(yīng)用里必須讓工作遠(yuǎn)離GUI線程,以便計算在后臺進(jìn)行時,屏幕能得到重繪。

              但實現(xiàn)并發(fā)是有難度的。不僅目前的語言和工具仍未為將應(yīng)用轉(zhuǎn)化為并行程序做好充分準(zhǔn)備,而且在主流應(yīng)用中也很難找到并行,尤其糟糕的是——并發(fā)要求程序員以人類難以適應(yīng)的方式思維。

              不過,多核在未來不可回避,我們必須找到與之相適應(yīng)的軟件開發(fā)方式。接下來,我們將深入探討并發(fā)的難度所在,以及一些未來可能的應(yīng)對方向。

            軟件新紀(jì)元

              今天的并發(fā)編程語言和工具幾乎與結(jié)構(gòu)化編程時代初期的順序化編程同時起步。信號量和協(xié)程是實現(xiàn)并發(fā)的基本手段,鎖與線程建立在更高層次,可以結(jié)構(gòu)化構(gòu)造并發(fā)程序。而我們需要的是以面向?qū)ο鬄榛A(chǔ)的并發(fā)——建立在更高層次的抽象有助于構(gòu)建并發(fā)程序,就像面向?qū)ο蟪橄笥幸嬗跇?gòu)建大型組件化程序一樣。

              幾個因素決定了并發(fā)變革對我們沖擊可能比面向?qū)ο蟠蟆J紫龋l(fā)是獲得更高性能的必需手段。像C之類的語言,無視面向?qū)ο螅阅茉诤芏嚅_發(fā)領(lǐng)域發(fā)揮作用。如果并發(fā)變成了應(yīng)用性能提升的華山一條路,那么商業(yè)和系統(tǒng)語言的存在價值就只能建立在支持并發(fā)編程的基礎(chǔ)上。因此現(xiàn)存的如C之類的語言,就必須支持超越pthreads之流簡單模式以外的并發(fā)特性,不能支持并發(fā)編程的語言將逐步走向消亡,而僅僅能在現(xiàn)代硬件不重要的場合占得一席之地。

              并發(fā)比面向?qū)ο鬀_擊更大的第二個原因是,盡管順序化編程已經(jīng)很難,但并發(fā)編程更難。例如,在分析順序化程序時,環(huán)境相關(guān)性分析是考量環(huán)境影響行為的基礎(chǔ)技術(shù)。并發(fā)程序則還需要進(jìn)行同步分析,而同時做環(huán)境相關(guān)性和同步分析已經(jīng)被證明不可企及

              最后,人類在遭受并發(fā)的突然襲擊后,發(fā)現(xiàn)并發(fā)程序比順序化代碼難以把握得多。即使最細(xì)心的程序員,也很可能考慮不到簡單半有序作業(yè)集里的交叉問題。

            客戶端和服務(wù)端應(yīng)用的差別

              對客戶端應(yīng)用來說,并發(fā)是一個挑戰(zhàn)。但是在很多服務(wù)端程序里,并發(fā)則是一個“已經(jīng)解決的問題”,我們可以例行公事般地構(gòu)造并發(fā)應(yīng)用,結(jié)果它就能很好工作,盡管進(jìn)一步改進(jìn)程序以確保其更具擴(kuò)展性,仍需艱巨努力。這些程序通常都包含大量并行,因為它們同時處理的是大量的彼此無關(guān)的請求。比如Web服務(wù)器和網(wǎng)站,運行的是同樣代碼的副本,處理絕大多數(shù)時候彼此無關(guān)的數(shù)據(jù)。

              而且,它們的執(zhí)行環(huán)境被隔離,通過高度支持并發(fā)存取結(jié)構(gòu)化數(shù)據(jù)的數(shù)據(jù)庫之類的抽象數(shù)據(jù)訪問方式實現(xiàn)狀態(tài)共享。因此,代碼通過數(shù)據(jù)庫實現(xiàn)數(shù)據(jù)共享,就能得到“安寧從容的感覺”——就好像運行在一個整潔、單線程的世界一樣。

              而客戶端應(yīng)用的世界里,則沒有那么規(guī)則和結(jié)構(gòu)化。通常,客戶端程序為單用戶執(zhí)行相關(guān)的小型運算,由此出發(fā),我們發(fā)現(xiàn)可以通過將運算分割為多個更有效率的小片斷來實現(xiàn)并發(fā)。也就是說讓用戶界面和程序運算小片斷可能以多種方式交互和共享數(shù)據(jù)。但這類程序難以并發(fā)執(zhí)行,因為其代碼是非均態(tài)的,結(jié)構(gòu)密織、交互復(fù)雜,而且操作的是基于指針的數(shù)據(jù)結(jié)構(gòu)。

            并行

              ·編程模型(Programming Models)

              現(xiàn)在,你能用多種方式實現(xiàn)并行,但每種方式僅僅適用于特定類型程序。大多數(shù)時候,沒有細(xì)致入微的設(shè)計與分析,很難事先知道哪種模型適合給定問題。如果無法清楚確定給出的問題能套用哪種模型,往往就必須將多個模型雜合起來靈活運用。

              這些并行編程模型可以從以下兩個方面明確加以區(qū)分:并行作業(yè)的粒度,和任務(wù)間的耦合程度。這兩個方面的不同,造就了迥異的編程模型。我們接下來依次討論。

              并行作業(yè),小到單個指令,比如加法和乘法運算,大到需花費數(shù)小時甚至數(shù)天的程序。顯然,并行體系中小作業(yè)的累計耗費是巨大的,因此,像并行指令運算等一般要求用硬件實現(xiàn)。與多處理器結(jié)構(gòu)相比,多核處理器減少了通訊和同步消耗,因此減少了小片代碼的累計成本。同樣,一般來說,粒度劃分越小,就越要注意拆分任務(wù)、以及為它們提供彼此間通訊和同步的成本。

              另一方面是作業(yè)在通訊和同步時的耦合程度。不要有這樣的幻想:作業(yè)完全獨立執(zhí)行,最后產(chǎn)生完全不同的輸出。在這種情況下,各作業(yè)有序執(zhí)行,不會引發(fā)同步和通訊問題,很容易實現(xiàn)無數(shù)據(jù)競爭可能的編程。這樣的情況是罕見的,絕大多數(shù)程序的并發(fā)作業(yè)都要共享數(shù)據(jù)。因此作業(yè)更為變化多端,保證其正確和高效的復(fù)雜性也大為增加。最簡單的情況是每個任務(wù)執(zhí)行完全一樣的代碼。這種類型的共享常常是規(guī)則的,通過對單個任務(wù)的分析就能理解。更具挑戰(zhàn)性的是不規(guī)則并行,這個時候,各作業(yè)的情況互不相同,共享模式更難于理解。

              ·無依賴并行(Independent parallelism)

              可能最簡單、只具有基本行為的模型是無依賴并行(有時候也叫密集并行(EP,Embarrassingly Parallel)),一個或者多個作業(yè)獨立運行,處理分離的數(shù)據(jù)。

              小粒度數(shù)據(jù)并行依賴于并發(fā)執(zhí)行的作業(yè)的獨立性。它們應(yīng)該無輸入輸出數(shù)據(jù)的共享、無交叉執(zhí)行,比如:

              double A[100][100];

              …

              A = A * 2;

              求得100×100數(shù)組每個元素與2的乘積,然后保存到原元素位置。100000次的乘法運算都獨立運行,彼此沒有交叉。它可能是比大多數(shù)計算機的實際需要更理想化的并行模型,粒度很小,因此實際應(yīng)用中通常會將矩陣分成n×m個塊,然后在這些塊的基礎(chǔ)上執(zhí)行并行計算。

              而在粒度軸的另一端,很多應(yīng)用,比如搜索引擎,共享僅僅一個巨型只讀數(shù)據(jù)庫,因此要求并行查詢沒有交叉。同樣,大規(guī)模仿真系統(tǒng)要求很多并行程序同時訪問包含輸入?yún)?shù)的大型空間,這是一個讓人頗感棘手的并行應(yīng)用。

              ·規(guī)則并行(Regular parallelism)

              比無依賴并行略為復(fù)雜的是計算工作彼此依賴時,將同樣的操作應(yīng)用到一個數(shù)據(jù)集上。如果在兩個操作間需要通訊或同步,則操作間存在依賴。

              我們考慮以下用四個相鄰元素的平均值替換數(shù)組中每個元素的運算模型:

              A[i, j] = (A[i-1, j] + A[i, j-1] + A[i+1, j] + A[i, j+1]) / 4;

              這類運算要求細(xì)致協(xié)調(diào),確保在用平均值替換前,已經(jīng)準(zhǔn)備好數(shù)組中相鄰數(shù)據(jù)。如果不考慮空間消耗,可以將計算得到的平均值寫入一個新數(shù)組。一般,其他更結(jié)構(gòu)化的計算策略,比如用Diagonal Wavefront算法訪問數(shù)組,會得到同樣的結(jié)果,而且有更好的緩存尋址和更低的內(nèi)存消耗收益。

              規(guī)則并行程序可能需要同步控制,或者精心排練的執(zhí)行策略,以確保得到正確的結(jié)果,但不像普通并行,它可以通過分析隱藏在操作后面的代碼以確定怎樣實現(xiàn)并行,并知道如何共享數(shù)據(jù)。

              再次移到粒度軸的另一端,譬如Web站點上的運算工作,除了訪問相同數(shù)據(jù)庫,存在典型的獨立性。因此除了數(shù)據(jù)庫事務(wù),所有的運算都并行進(jìn)行,不需要大量協(xié)調(diào)工作。

              ·無結(jié)構(gòu)并行(Unstructured parallelism)

              大多數(shù)情況下,最沒有規(guī)律的并行形式是并行運算彼此不同,因此它們的數(shù)據(jù)訪問無可預(yù)測,需要通過顯式同步加以協(xié)調(diào)。這是使用多線程和顯式同步編寫的程序里最常見的并行形式,其中的線程在程序里扮演著互不相同的角色。一般,對于這種并行形式,除了知道兩個線程訪問數(shù)據(jù)發(fā)生沖突時需要顯式同步,我們在其他方面很難說出個頭頭道道;另外,這類程序具有不確定性。

              ·狀態(tài)共享存在的問題;鎖的局限性

              無結(jié)構(gòu)并行面臨的又一個挑戰(zhàn)來源于無結(jié)構(gòu)狀態(tài)共享。客戶端應(yīng)用通常通過共享內(nèi)存的辦法來解決對象圖(Graphs of Objects)中交互行為無可預(yù)測的問題。

              假設(shè)兩個任務(wù)希望訪問同一個對象,其中一個可以修改對象的狀態(tài),如果我們不加控制,那么就會產(chǎn)生數(shù)據(jù)競爭。競爭的后果很糟糕,并發(fā)任務(wù)可能讀寫到不一致或已損毀的數(shù)據(jù)。

              有大量同步策略可以解決數(shù)據(jù)競爭問題,其中最簡單的就是鎖。每一個需要訪問共享數(shù)據(jù)片的任務(wù)在訪問數(shù)據(jù)前必須申請得到鎖,然后執(zhí)行計算;最后要釋放鎖,以便其他任務(wù)可以對這些數(shù)據(jù)執(zhí)行別的操作。不幸的是,盡管鎖在一定程度上能避免數(shù)據(jù)競爭,但它也給現(xiàn)代軟件開發(fā)帶來了嚴(yán)重問題。

              最主要的問題是,鎖不具有可組合性。你不能保證由兩部分以鎖為基礎(chǔ)、能正確運行的代碼合并得到的程序依然正確。而現(xiàn)代軟件開發(fā)的基礎(chǔ)恰恰是將小程序庫合并為更大程序的組裝能力;因此,我們無法做到不考察組件的具體實現(xiàn),就能在它們基礎(chǔ)上組裝大軟件,這是個大問題。

              造成組裝失敗的禍?zhǔn)资撬梨i。考慮最簡單的情況,當(dāng)兩個任務(wù)以相反順序申請兩個鎖時,死鎖就出現(xiàn)了:任務(wù)T1獲得了鎖L1,任務(wù)T2獲得了鎖L2,然后,T1申請獲得鎖L2,同時T2申請獲得L1。此時,兩個任務(wù)將永久阻塞。而被以相反順序請求兩個鎖的情況在任何時候都可能發(fā)生,所以獲得一個鎖后,只有讓調(diào)用進(jìn)入你無法控制代碼的內(nèi)部,才可能找到解決死鎖問題的辦法。

              但是,那些可擴(kuò)展的框架卻沒有考慮這個問題。即使目前最根正苗紅的商業(yè)應(yīng)用框架也是這么干的,包括.NET框架、Java標(biāo)準(zhǔn)庫等。之所以沒出什么大問題,是因為開發(fā)人員仍然沒有編寫要求頻繁鎖定的大量并發(fā)的程序。很多復(fù)雜模型希望解決死鎖問題——比如實現(xiàn)退避/重送(backoff-and-retry)協(xié)議——但這些模型都需要程序員經(jīng)受嚴(yán)格訓(xùn)練,并且一些解決辦法還可能引入其他問題(比如活鎖(或空轉(zhuǎn),livelock))。

              通過確保所有鎖申請都只能在安全順序基礎(chǔ)上得到滿足的死鎖預(yù)防技術(shù),也無能為力。例如鎖調(diào)整與鎖分級策略,要求所有同級鎖按照預(yù)定順序一次滿足,此后只能申請獲得更高級別的單一鎖,以此的確可以避免鎖沖突。這類技術(shù)雖然在實踐中還未普及,不過在單一團(tuán)隊維護(hù)的模塊和框架內(nèi)已經(jīng)發(fā)揮了作用。但是,它們要求對全部代碼的完全控制。這就嚴(yán)重限制了這些技術(shù)在可擴(kuò)展框架、插件系統(tǒng)和其他需要將多方編寫的代碼整合環(huán)境里的應(yīng)用。

              一個更基本問題是,鎖的實現(xiàn)依賴于程序員對協(xié)定的嚴(yán)格遵循。鎖與它所保護(hù)的數(shù)據(jù)間關(guān)系相當(dāng)隱諱,只能通過程序員的紀(jì)律性得到維系。程序員必須總能清楚記得訪問共享數(shù)據(jù)前,要在正確地點放置恰當(dāng)?shù)逆i。有時,程序里的鎖管理協(xié)定的確存在,但它們幾乎從來沒有精確到可供工具實現(xiàn)檢驗。

              鎖還有其他一些更加微妙的問題。鎖定是一個全局屬性,很難被本地化到單個過程、類或者框架。所有訪問共享數(shù)據(jù)片的代碼都必須知道且服從鎖約定,無論是誰編寫這些代碼,代碼用在什么地方。

              即便將同步本地化,也并非任何時候都能正常工作。拿一個常見解決方案,如Java中的synchronized方法來說。對象的每個方法都能從對象得到一個鎖,所以沒有任何兩個線程可以同時直接訪問對象的狀態(tài)。而對象狀態(tài)僅能通過對象的方法訪問,程序員又記得給方法增加了synchronized聲明,如此一來,看似達(dá)到了我們的目的。

              而實際上,synchronized方法至少有三個主要的問題。首先,它們不適合于其方法會調(diào)用別的對象(比如Java的Vector和.NET的SyncHashTable)的虛函數(shù)的類型,因為獲得一個鎖后調(diào)用進(jìn)入第三方代碼,就可能引發(fā)死鎖。其次,synchronized方法可能導(dǎo)致頻繁鎖定,因為它們要求在所有的對象實例上獲得和釋放鎖,即便很多對象從不存在線程交互。第三,synchronized方法的鎖粒度過小,當(dāng)程序在單或多個對象上調(diào)用多個方法時,無法保證操作的原子性。我們以如下簡單的銀行事務(wù)為例:

              account1.Credit(amount); account2.Debit(amount)

              逐對象(Per-object)鎖定可以保護(hù)每個調(diào)用,但不能阻止其他線程看到兩個賬戶在多次調(diào)用之間的不一致信息。這種類型的操作,原子性與單個調(diào)用的邊界不吻合,因此需要額外的、顯式同步。

              ·鎖的替代者

              考慮到內(nèi)容完整性,我得提一下鎖的兩個主要備選方案。一個是無鎖編程(Lock-Free Programming)。通過對處理器內(nèi)存模式的深入認(rèn)識,建立可共享但無顯式鎖定的數(shù)據(jù)結(jié)構(gòu)是可能的。無鎖編程難度很大且非常脆弱,因此新的無鎖數(shù)據(jù)結(jié)構(gòu)實現(xiàn)方案,仍在不斷修改之中。

              第二個替代物是事務(wù)內(nèi)存(Transactional Memory),它將數(shù)據(jù)庫中事務(wù)模式的核心思想移植到編程語言里來。程序員將自己的程序編寫為一個個具有確定原子性的塊,它們可以分離執(zhí)行,因此只有在每個原子行為執(zhí)行前和執(zhí)行后,并發(fā)操作才能訪問共享數(shù)據(jù)。盡管很多人看好事務(wù)內(nèi)存的前途,但它目前仍處于研究之中。

             

            對語言的要求

              ·我們需要何種編程語言

              我們需要更高層次的語言抽象,要讓目前的命令式語言進(jìn)化式擴(kuò)展,這樣,現(xiàn)存的應(yīng)用才能快速實現(xiàn)并發(fā)執(zhí)行。無論是初始開發(fā)階段,還是維護(hù)階段,編程模型都必須讓并發(fā)易于理解和實現(xiàn)。

              ·顯式、隱式和自動并行

              顯式編程模型提供的抽象要求程序員能明確定位并發(fā)出現(xiàn)的位置。其主要優(yōu)點是,它允許程序員充分利用各自在應(yīng)用領(lǐng)域的知識,充分挖掘應(yīng)用的并發(fā)潛能。不足在于面對共享數(shù)據(jù)時,要求程序員高度熟練,以實現(xiàn)新的更高層次的編程抽象模型。

              隱式編程模型將并發(fā)隱藏在庫和API包內(nèi)部,因此在庫以并行方式執(zhí)行工作時,程序員得以持續(xù)保有全局視野。這種方式可以讓初級程序員安全使用并發(fā)。主要弱點是難以獲得并發(fā)的全部性能收益。另外,也很難設(shè)計出在任何場合都不暴露并發(fā)的接口——比如,當(dāng)程序?qū)⒉僮鲬?yīng)用在相同數(shù)據(jù)的多個實例時。

              另一個正被廣泛研究的方法是自動并行,編譯器試圖自動找到并行部分,通常應(yīng)用于Forthan之類老式語言編寫的程序里。聽起來很吸引人哦,但這種辦法在實踐中不大行得通。必須有對程序的精確分析,才能弄清程序的潛在行為。而對Forthan之類簡單語言做這類分析就頗具挑戰(zhàn)性了,面對像C這樣的以指針為基礎(chǔ)操作數(shù)據(jù)的語言,更是難上加難。再說,順序式程序通常使用的是順序式算法,能實現(xiàn)并發(fā)的部分非常有限。

              ·命令式和函數(shù)式語言

              流行商用編程語言(如Pascal、C、C++、Java和C#)都是命令式語言,在這些語言里,程序員分步指定對變量和數(shù)據(jù)結(jié)構(gòu)的變化。小粒度控制構(gòu)造(如循環(huán))、低層次數(shù)據(jù)操作和共享易變對象實例等因此,使以這些語言編寫的程序難以分析并實現(xiàn)自動并行。

              我們通常相信函數(shù)式語言,如Scheme、ML和Haskell等,能夠鏟除這類障礙,因為它們就為并發(fā)而生。以這些語言寫成的程序,操作沒有并發(fā)危險、不需改變的對象實例。此外,它們沒有副作用,執(zhí)行順序上的限制很少。

              但實際中,函數(shù)式語言并不一定有益于并發(fā)。函數(shù)式程序中的并行主要執(zhí)行于過程調(diào)用層次,這對于傳統(tǒng)并行處理器來說,粒度過小。而且,大多數(shù)函數(shù)式語言允許操作可變對象時存在部分副作用,因此應(yīng)用了這些特性的代碼,也難以實現(xiàn)自動并行。

              這些語言為了增加表達(dá)能力和提高效率又引入了可變狀態(tài)。在純粹的函數(shù)式語言里,復(fù)合數(shù)據(jù)結(jié)構(gòu),如數(shù)組、樹等,是通過原結(jié)構(gòu)副本外加待修改數(shù)據(jù)實現(xiàn)更新的。這種方法從語義上講頗有魅力,但性能糟糕(線性算法很容易升級為二階算法)。此外,函數(shù)式更新對嚴(yán)格的順序式運算無能為力,此時,每個操作都會等待至上一個操作完成對程序狀態(tài)的更新才能執(zhí)行。

              函數(shù)式語言對于并發(fā)的真正貢獻(xiàn)是這些語言中廣泛采用的高層次編程方式,在這種方式下,像Map和Map-Reduce等操作會將計算應(yīng)用于復(fù)合數(shù)據(jù)結(jié)構(gòu)的所有元素。這種高層次的操作方式是并發(fā)的堅實基礎(chǔ)。這種編程風(fēng)格,幸運的是,這種編程方式?jīng)]有被固化于函數(shù)式語言,對命令式語言有重要借鑒意義。

              例如,Google的Jeffrey Dean和Sanjay Ghemawat描述過Google如何使用Map-Reduce實現(xiàn)大規(guī)模分布式計算。命令式語言可以開動腦筋將這些特性納為己用,并從中獲益。這一點重要,畢竟,我們的工業(yè)不能從頭再來。為了保護(hù)全世界對現(xiàn)存軟件的巨大投資,特別需要盡快增加對并發(fā)的支持,同時保護(hù)軟件開發(fā)人員擁有的命令式語言專業(yè)知識和經(jīng)驗。

            抽象優(yōu)化

              目前的大多數(shù)語言都在線程和鎖層次實現(xiàn)了顯式編程。這種抽象層次過低且難以系統(tǒng)化。這種架構(gòu)不足以成為構(gòu)建抽象的堅實基礎(chǔ),它縱容多線程程序隨意阻塞和重入(reentrancy),以致帶來很多問題。

              更高層次抽象允許程序員用自然方式表述任務(wù),此時,運行時系統(tǒng)能將這些任務(wù)有計劃調(diào)度,使之適配于計算機硬件。這將使應(yīng)用在新的硬件上獲得更好性能。另外,在常規(guī)開發(fā)中,程序員將得閑將精力放在任務(wù)內(nèi)部的順序執(zhí)行流程上來。

              有關(guān)更高層次抽象的兩個基本例子是異步調(diào)用和future。無阻塞函數(shù)和方法產(chǎn)生的是異步調(diào)用。調(diào)用者可繼續(xù)執(zhí)行,從概念上說,也就是消息被發(fā)送到任務(wù)或者fork進(jìn)程去獨立執(zhí)行操作。期貨(future)是一種從異步調(diào)用返回操作結(jié)果的機制,但目前僅是一個有價值的概念,還未具體實現(xiàn)。

              更高層次抽象的又一個例子是主動對象(Active Object),它運行在自有的線程里,因此創(chuàng)建1000個這樣的對象,就相當(dāng)于創(chuàng)建了1000個執(zhí)行線程。主動對象僅有一個方法在給定時間執(zhí)行,它扮演監(jiān)視器的角色,但不要求傳統(tǒng)意義上的鎖定。相反,來源于主動對象外部的方法調(diào)用是通過此對象匯集、編隊和派發(fā)異步消息實現(xiàn)的。從專業(yè)化的Actor語言到傳統(tǒng)C代碼的STA(Single-Threaded Apartment)式COM套件等,主動對象有很多種設(shè)計實現(xiàn)。

              其他更高層次抽象也是需要的,比如描述和檢測異步消息交換的協(xié)議。所有這些方法應(yīng)該被整合起來構(gòu)建一個統(tǒng)一的編程模型,從而滿足各主要粒度層次的典型應(yīng)用的并發(fā)要求。

            對工具的要求

              ·我們需要何種工具

              因為并行編程的固有難度和我們對它的不熟悉,必然需要更好的編程工具系統(tǒng)地幫助我們查漏補缺、調(diào)試程序、尋找性能瓶頸和測試程序。沒有這些工具,并發(fā)將成為提高開發(fā)和測試人員生產(chǎn)率的障礙,導(dǎo)致并發(fā)軟件成本更高,而質(zhì)量更低劣。

              并發(fā)會帶來不同于順序式代碼的新型程序錯誤。數(shù)據(jù)競爭(同步不足或死鎖造成)和活鎖(不適當(dāng)同步造成)缺陷難以發(fā)現(xiàn)和理解,因為其行為通常具有不確定性且難以重現(xiàn)。傳統(tǒng)調(diào)試方法,比如啟動前設(shè)置斷點再重新運行程序,對于執(zhí)行路徑和行為每次都可能發(fā)生變化的并發(fā)程序來說,無能為力。

              在并發(fā)世界里,系統(tǒng)級的缺陷檢測工具具有重大價值。這些工具利用靜態(tài)程序分析法系統(tǒng)地探測程序所有可能的執(zhí)行行為,因此它們能夠捕捉到不能重現(xiàn)的錯誤。盡管類似技術(shù),比如模型檢測,已經(jīng)在天生支持并發(fā)的硬件的缺陷探測中獲得重大成功,但在軟件中非常困難。大多數(shù)情況下,軟件的狀態(tài)空間比硬件大得多,因此這些系統(tǒng)探測虛擬狀態(tài)的技術(shù)還有很多工作要做。無論是硬件還是軟件,模塊化和抽象都是提高分析可行性的關(guān)鍵。在硬件模型測試中,如果你能將ALU (arithmetic logic unit)拆分為一個個寄存器做獨立分析,那么你的任務(wù)就變得很容易實現(xiàn)了。

              這就引出了軟件更難以分析的第二個原因:將軟件切分為眾多片段,做獨立分析,然后合并結(jié)果去看它們?nèi)绾我黄鸸ぷ饕y得多。共享狀態(tài)、不確定接口和格式不明的交互將使軟件分析任務(wù)的挑戰(zhàn)性大大增加。

              目前,并發(fā)軟件的缺陷檢測工具是個熱門研究領(lǐng)域。其中,微軟研究院的KISS(Keep it Strictly Sequential)是項有前途的技術(shù),它將多線程程序轉(zhuǎn)化為包括了原始的不超過兩個切換環(huán)境的線程的所有可能行為的順序式程序。轉(zhuǎn)換后的程序可以被大量現(xiàn)存的順序式工具分析,因此這些工具得以完成有限模型的并發(fā)缺陷檢測工作。

              即便我們?nèi)〉昧松鲜鲆恍┏煽儯绦騿T仍然需要優(yōu)秀的調(diào)試工具幫助他們理解并行程序里的復(fù)雜和難以重現(xiàn)的交互行為。有兩項常規(guī)技術(shù)可以收集這方面信息。一是更好的日志跟蹤工具,可以記錄哪一個消息被送到了哪個進(jìn)程或線程,進(jìn)程和線程又訪問了哪個對象,因此開發(fā)者可以回溯并部分理解程序的執(zhí)行行為。開發(fā)者也希望獲得追蹤跨線程因果關(guān)系(比如哪個消息傳遞到了主動對象,何時執(zhí)行,導(dǎo)致哪一個別的消息傳遞到了其他主動對象)、回放、重排隊列里的消息、步進(jìn)包含回調(diào)的異步調(diào)用模式,以及其他能力,借以檢測代碼的并發(fā)執(zhí)行行為。第二個辦法是重放執(zhí)行,它能讓程序員備份程序的執(zhí)行歷史,然后可重新執(zhí)行一些代碼。重放調(diào)試的想法由來已久,但它的高成本和復(fù)雜性導(dǎo)致了被拋棄的下場。最近,虛擬機監(jiān)視器(VMM,Virtual Machine Monitor)已經(jīng)逐漸呈現(xiàn)出取代這兩項技術(shù)的趨勢,未來的并發(fā)世界里,這項技術(shù)很可能成為必需品。

              并發(fā)世界也需要性能調(diào)試和調(diào)節(jié)方面的新工具。并發(fā)引入了新的性能瓶頸,比如鎖競爭(Lock Contention)、緩存一致性(Cache Coherence)管理和鎖護(hù)送效應(yīng)(Lock Convoys)等,這些問題依靠簡單工具是難以察覺的。對計算機底層和程序并發(fā)結(jié)構(gòu)更為敏感的新工具,將幫助我們更好的發(fā)現(xiàn)這些問題。

              測試領(lǐng)域,也必須發(fā)生變化。并發(fā)程序,因其不確定性行為,更難于測試。用以跟蹤語句和分支是否得到執(zhí)行的簡單代碼覆蓋測試方法,需要被擴(kuò)展以支持對其他并行執(zhí)行代碼的評估,否則測試將提供不符實際的反應(yīng)程序執(zhí)行完整度的優(yōu)化結(jié)果圖。另外,簡單壓力測試也需要通過更多地使用類似模塊檢測技術(shù)以探測系統(tǒng)狀態(tài)空間的系統(tǒng)級技術(shù)加以擴(kuò)充。比如,Verisoft使用這些技術(shù)在尋找電話交換軟件錯誤方面已經(jīng)取得相當(dāng)成功。現(xiàn)在,很多并發(fā)應(yīng)用通過加大測試時的壓力大小來建立應(yīng)用不太可能遭受嚴(yán)重競爭的信心。未來,這將愈加顯得不夠,軟件開發(fā)者將必須以嚴(yán)格的確定性測試代替基于壓力測試的想當(dāng)然,來證明他們產(chǎn)品的質(zhì)量。

            并行是關(guān)鍵

              并發(fā)解決方案將是軟件史上的一次重大變革。其難點不在于多核硬件的構(gòu)建,二是讓主流應(yīng)用從持續(xù)爆炸式增長的CPU性能中獲益的編程方式。

              軟件工業(yè)必須重歸現(xiàn)存應(yīng)用在新硬件上更快運行的跑道。為此,我們必須開始學(xué)習(xí)編寫包含至少數(shù)十最好數(shù)百可分離任務(wù)(當(dāng)然不是說同時處于活動狀態(tài))的并發(fā)應(yīng)用。

              并發(fā)也開啟了新的可能,那就是讓軟件功能更多、能力更強。這就要求我們積極發(fā)揮想象力,找到挖掘并利用新處理器指數(shù)級增長的潛能的辦法。

              為了促成軟件目標(biāo)的早日實現(xiàn),程序語言設(shè)計師、系統(tǒng)構(gòu)建者和編程工具創(chuàng)造者需要開始努力思考并行,找到比目前成為并行程序構(gòu)建基礎(chǔ)的低層次線程工具和顯式同步更好的技術(shù)。我們需要更高層次的并行構(gòu)建實現(xiàn),借此更清楚表述開發(fā)人員的意圖,以使程序的并行架構(gòu)更加明晰,更容易理解,更能被工具驗證。

            posted on 2007-09-23 09:33 小石頭 閱讀(308) 評論(0)  編輯 收藏 引用

            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            99国产精品久久久久久久成人热| 国产国产成人久久精品| 久久精品人妻一区二区三区| 国产精品久久精品| 国产精品久久久久久久久| 久久精品人人做人人爽电影蜜月| 欧美精品乱码99久久蜜桃| 欧美日韩精品久久久久| 亚洲级αV无码毛片久久精品| 久久99热这里只有精品国产| 国产A三级久久精品| 性做久久久久久久| 久久99精品久久久久久 | 久久综合狠狠综合久久激情 | 精品蜜臀久久久久99网站| 久久精品国产一区二区三区日韩| 青青热久久综合网伊人| 久久精品成人欧美大片| 久久久无码精品亚洲日韩京东传媒| 97视频久久久| 精品综合久久久久久97超人 | 狠狠色丁香久久婷婷综合蜜芽五月| 久久精品99无色码中文字幕| 中文字幕无码久久人妻| 国产亚洲精久久久久久无码| 国产精品久久久久无码av| 精品久久久久久99人妻| 久久精品国产免费观看 | 人人狠狠综合88综合久久| 狠狠色丁香婷婷久久综合| 91精品国产高清久久久久久io| 亚洲国产精品婷婷久久| 一本色综合久久| 久久精品国产精品青草| 久久人人爽人人爽人人片AV东京热| 中文无码久久精品| 久久噜噜久久久精品66| 久久er99热精品一区二区| 久久乐国产精品亚洲综合| 久久九九亚洲精品| 午夜欧美精品久久久久久久|