無堵塞的併發程式設計

banq發表於2011-10-06
順序程式設計非常普及,可以說是大多數程式設計師程式設計正規化,只不過可能他們沒有意識到,如今已經進入併發程式設計時代,順序程式設計和併發程式設計是兩種完全不同的程式設計思路,堵塞Block是順序程式設計的家常便飯,常常隱含在順序程式式程式設計中難以發現,最後,成為殺死系統的罪魁禍首;但是在併發程式設計中,堵塞卻成為一個目標非常暴露的敵人,堵塞成為併發不可調和絕對一號公敵。

因為無堵塞所以快,這已經成為併發的一個基本特徵。

過去我們都習慣了在一個執行緒下的順序程式設計,比如,我們寫一個Jsp(PHP或ASP)實際都是在一個執行緒
下執行,以google的adsense.Jsp為例子:

<%
//1.獲得當前時間
long googleDt = System.currentTimeMillis();
//2.建立一個字串變數
StringBuilder googleAdUrlStr = new StringBuilder(PAGEAD);
//3.將當前時間加入到字串中
googleAdUrlStr.append("&dt=").append(googleDt);
//4.以字串形成一個URL
URL googleAdUrl = new URL(googleAdUrlStr.toString());
%>
<p class="indent">


以上JSP中4步語句實際是在靠一個執行緒依次順序執行的,如果這四步中有一步執行得比較慢,也就是我們所稱的是堵塞,那麼無疑會影響四步的最後執行時間,這就象烏龜和兔子過獨木橋,整體效能將被跑得慢的烏龜降低了。
過去由於是一個CPU處理指令,使得順序程式設計成為一種被迫的自然方式,以至於我們已經習慣了順序執行的思維;但是如今是雙核或多核時代,我們為什麼不能讓兩個CPU或多個CPU同時做事呢?

如果兩個CPU同時執行上面程式碼會有什麼結果?首先,我們要考慮兩個CPU是否能夠同時執行這段邏輯呢?
首先,上面程式碼中第二步是不依賴第一步的,因此,第一步和第二步可以交給兩個CPU同時去執行,然後在第三步這裡堵塞等待,將前面兩步執行的結果在此組裝。很顯然,由於第三步的堵塞等待,使得兩個CPU平行計算匯聚到這一步又變成了瓶頸,從而並不能充分完全發揮兩個CPU平行計算的效能。

我們把這段JSP的第三步程式碼堵塞等待看成是因為業務功能必須要求的順序程式設計,無論前面你們如何分開跑得快,到這裡就必須合攏一個個過獨木橋了。

但是,在實際技術架構中,我們經常也會因為非業務原因設定人為設定各種堵塞等待,這樣的堵塞就成為並行的敵人了,比如我們經常有(特別是Socket讀取)
While(true){
……
}
這樣的死迴圈,無疑這種無限迴圈是一種堵塞,非常耗費CPU,它也無疑成為並行的敵人。比如JDK中java.concurrent.BlockingQueue LinkedBlockingQueue,都是一種堵塞式的所謂並行包,這些並行功能必須有堵塞存在的前提下才能完成並行執行,很顯然是一種偽並行。

由於各種技術上的堵塞存在,包括多執行緒中鎖機制,也是一種堵塞,因為鎖機制在某個時刻只允許一個執行緒進行修改操作,所以,併發框架Disruptor可以自豪地說:無鎖,所以很快。

現在非常流行事件程式設計模型,如Event Sourcing或Domain Events或Actor等等,事件程式設計實際是一種無堵塞的並行程式設計,因為事件這個詞語本身有業務模型上概念,也有技術平臺上的一個規範,談到事件,領域專家明白如同電話鈴事件發生就要接,程式設計師也能明白只要有事件,CPU就要立即處理(特別是緊急事件),而且事件發生在業務上可能是隨機的,因此事件之間難以形成互相依賴,這就不會強迫技術上發生前面Jsp頁面的第三步堵塞等待。

因此,在事件模型下,預設程式設計思維習慣是併發並行的,如果說過去我們預設的是進行一個執行緒內的順序程式設計,那麼現在我們是多執行緒無鎖無堵塞的併發程式設計,這種習慣的改變本身也是一種思維方式的改變。

在預設大多數是併發程式設計的情況下,我們能將業務上需要的順序執行作為一種特例認真小心對待,不要讓其象癌細胞一樣擴散。我們發現這種業務上的順序通常表現為一種高一致性追求,更嚴格的一種事務性,每一步依賴上一步,下一步失敗,必須將上一步回滾,這種方式是多核CPU剋星,也是分散式平行計算的死穴。值得慶幸的是這種高一致性的順序程式設計在大部分系統中只佔據很小一部分,下圖是電子商務EBay將他們的高一致性侷限在小部分示意圖:

由此可見,過去我們實現的順序程式設計,實際上是我們把一種很小眾的程式設計方式進行大規模推廣,甚至作為預設的程式設計模式,結果導致CPU閒置,吞吐量上不去同時,CPU負載也上不去,CPU出工不出力,如同過去計劃經濟時代的人員生產效率。

所以,綜上所述,以事件程式設計為正規化的無堵塞併發是一種趨勢,下面關鍵問題是哪種事件程式設計正規化更簡單,更易於被程式設計師理解掌握了。

相關話題:

為什麼要用Event Sourcing?

相關文章