正如大家所知道的那樣,多核多cpu越來越普遍了,而且編寫多執行緒程式也是件很簡單的事情。在windows下面,呼叫createthread函式一次就能夠以你想要的函式位址新建乙個子執行緒執行。然後,事情確實你發現建立多執行緒根本沒有讓程式快多少,也沒有提高多少cpu利用率,甚至可能讓cpu利用率下降。唯一能夠確定的是多執行緒能夠避免介面假死。為什麼會是這樣的了。本文將舉一些例子和講述一些原因。
首先,我來講一下多處理的一些知識。如下圖所示,
多處理器系統也只有乙個待執行的執行緒佇列,記憶體中也只有乙個作業系統拷貝,而且也只有乙個記憶體系統,但是會有多個cpu同時執行不同的執行緒。乙個cpu執行乙個執行緒,那麼上圖中的系統最多能在同一時間執行2個執行緒。其實,多處理系統需要掌握的知識不是這些,而是快取一致性。
現在來解釋下什麼是快取一致性。由於,還是只有乙個記憶體系統。所有cpu都要和這個記憶體系統通訊,但是只有一條匯流排,那麼這無疑會造成匯流排緊張,限制整體的速度了。那麼,你多個cpu也沒多少意義了。解決這個問題的辦法還是利用cpu的快取機制,學過組成原理的同學都知道,cpu的快取命中率還是很高的,有90%以上吧。那麼,我繼續利用快取機制還是可以降低匯流排的頻繁使用的。但是,每個cpu都有自己的快取。如果有2個cpu的快取儲存的是同一記憶體資料的內容,其中乙個cpu的快取更新了,另外乙個cpu的快取也必須更新,這就是所謂的快取一致性。程式設計多執行緒程式的乙個很重要的一點就是避免因為快取一致性引起的快取更新風暴。
現在我舉乙個快取更新風暴的例子。
如圖所示的類定義,
因為總有些子任務是可以併發的,多個子任務併發執行了很可能就能夠避免cpu需要io操作的完成了,而且能夠提高系統的吞吐量。
方法二,快取多執行緒的共享資料。
當你已經在使用多執行緒了,很多時候必須使用共享資料。如果,資料是唯讀的,那麼可以在第一次獲取後儲存起來,以後就可以重複使用了。但是,第一次的獲取還是無法避免的需要執行緒同步操作的。
方法三,如果執行緒數目有限,就不要共享資料。
做法是為每乙個執行緒例項化乙個單獨的資料,其實就是為每乙個執行緒分配一塊資料使用。這樣沒有執行緒同步操作了,速度可以盡可能的提示。
方法四,如果沒辦法確定執行緒數目到底有多少,那麼使用部分共享吧。
部分共享其實就是使用多個資源池代替乙個資源池,資源池的數目得更加經驗來確定。如下圖所示,
最後在提乙個叫做thundering herd的問題,該問題維基百科有定義大意是,當多個執行緒在等待乙個資源的時候,如果事件等待到了,作業系統是喚醒所有等待的執行緒讓它們自己去競爭資源了還是選擇乙個執行緒把資源給它。當然喚醒所有的執行緒肯定開銷要大,而且所有沒有搶到資源的執行緒還得重新進入等待狀態,這無疑造成很多沒必要的操作,浪費了沒必要的執行緒上下文切換。總之,會不會存在thundering herd還是跟不同的作業系統有關的。萬一存在thundering herd了,多執行緒可能就沒那麼好辦了。
到現在我們知道了為什麼多cpu並不能成倍提高程式的速度了。首先因為有些任務無法並行,其次即使是並行cpu之間還是有很多牽制的。本書的內容主要來自提高c++效能的程式設計技術一書。
如何提高多執行緒程式的cptgju利用率
因為總有些子任務是可以併發的,多個子任務併發執行了很可能就能夠避免cpu需要io操作的完成了,而且能夠提高系統的吞吐量。方法二,快取多執行緒的共享資料。當你已經在使用多執行緒了,很多時候必須使用共享資料。如果,資料是唯讀的,那麼可以在第一次獲取後儲存起來,以後就可以重複使用了。但是,第一次的獲取還是...
利用多執行緒提高程式效能(for Android)
首先我們建立了乙個http客戶端和http請求。如果請求成功,就把響應中包含的內容解碼成位圖格式並返回,以備後續使用。另外補充一句,為了讓程式可以訪問網路,必須在程式的manifest檔案中宣告使用internet。注意 舊版的bitmapfactory.decodestream有個bug,可能使得...
多執行緒程式占用CPU過多的問題
這幾天在做windows服務這塊,涉及到socket和多執行緒問題,功能都已經實現了的,不過在除錯的時候發現,服務不管在用不用就是無倫什麼時候,始終佔了很多cpu,25 著實嚇了一跳。後來想一想,主要是乙個監聽子執行緒一直在後台執行,片刻也不休息一下,不管有沒有任務請求他一直都在跑。這樣不累才怪了。...