天天看點

使用多線程的利弊

 <b>1.Amdahl</b><b>定律</b>

     一個很簡單的量化公式,用來計算一個程式中串行部分所占多少對程式加速比的影響或者用來計算計算機硬體配置中某個裝置的速度提高能夠将整個系統的速度提高多少。

     假設一個串行程式執行的總時間為1,不能被并行化的部分占的時間比例為p,即串行化的部分為p,可并行化的時間為:1-p。如果用n個核用來加速的話,加速比為:

<a href="http://blog.51cto.com/attachment/201206/220547749.png" target="_blank"></a>

    如果一個程式中隻有50%部分能夠被并行化,那麼即使使用100個核,能達到的最好的加速比為1.98,即不會達到2.除非n無窮大。

     Amdahl就像克萊姆準則一樣不能用于實際中,因為很難精确的使用這個公式。我們需要找到程式中所有的串行部分和并行部分。串行部分不僅僅存在于代碼中必需的依賴關系,可能還有底層庫函數中的串行,還有作業系統的串行部分,甚至還有硬體本身的串行部分。

<b> </b>

<b>2.</b><b>異步應用程式的實作方法</b><b></b>

<b></b>

     常見的實作方式有:多線程+同步,異步I/O,非阻塞I/O,信号,事件。異步I/O和非阻塞I/O并不是一回事,當然在有些場合下也會混淆使用。一般來說,異步側重于表達并行,兩個執行流可以同時進行。非阻塞一般還包含一個查詢的過程,因為要查詢所要進行的操作是否完成。

     異步I/O使用起來難度比多線程大,了解和維護起來的難度一般也比多線程麻煩。同樣使用信号也是這個缺點,因為單個線程可以使用同步的方式,線程之間可以使用信号來通信。這樣就好像一個人同時做很多件事情和一個團隊來協作來完成這些事情的差別一樣。後者的執行邏輯會更加清晰,而且多線程+同步的方式能夠實作所有異步I/O帶來的優勢。

     使用UNIX信号的方式有嚴重的局限性,因為收到信号後所有的邏輯放在一個信号處理函數中執行,這并不是信号處理函數設計的初衷。而且,使用信号會顯得程式的組織結構比較混亂,維護起來比較麻煩。

     事件流也是實作異步應用程式的一種方式。一般系統底層會将應用程式收到的各種事件緩沖到一個隊列中,然後又底層負責将各種事件對應到一個回調函數上,串行的處理各個事件,即調用各個回調函數。這種方式的最大缺點就是有些事件的回調函數的執行事件比較長,會導緻其他事件不能得到很好地相應。在Windows系統的.NET架構上,事件+回調函數是使用的比較多的一種方式。事件流的缺點在于其處理的順序性。當然事件流+回調函數+多線程是一種不錯的選擇。

<b>3.</b><b>程式設計模型</b><b></b>

     各個程式設計模型的計算能力是等價的,但是對問題抽象層次是不同的。彙編語言在表示程式的結構方面顯得比較笨拙,但是使用C語言就将程式的設計結構顯式的表現出來了。使用C語言進行資料封裝和多态處理顯得很笨拙,使用C++就能很好地處理這個問題。使用關系資料庫在解決大規模資料問題上顯得很笨拙,使用Map-Reduce就能很好的處理某些問題。非線程代碼不能顯式的表達操作的同步性,使用線程代碼就能很好的表達出這些同步性。線程源代碼讓獨立的子產品或者松耦合的子產品更加清楚的表現出來。

     不同的程式設計模型對應着不同的抽象層次,對于問題域的抽象恰到好處的抽象模型有助于我們解決更複雜的問題。

<b>4.</b><b>什麼情況下使用線程</b><b></b>

     使用線程是有代價的,如果程式是計算密集型且每一步都有依賴,那麼使用線程反而會導緻效率下降,因為多個線程之間需要切換,還要負責維護鎖,信号量等設施。對于可并行的計算密集型問題和I/O與計算可重疊的問題使用多線程一般會達到顯著的效果。程式中有多個可并發的子產品的時候,使用線程也能提高程式的響應速度。

本文轉自hipercomer 51CTO部落格,原文連結:http://blog.51cto.com/hipercomer/909006