技術分享:Linux多核並行程式設計關鍵技術
多核並行程式設計的背景
在摩爾定律失效之前,提升處理器效能透過主頻提升、硬體超執行緒等技術就能滿足應用需要。隨著主頻提升慢慢接近撞上光速這道牆,摩爾定律開始逐漸失效,多核整合為處理器效能提升的主流手段。現在市面上已經很難看到單核的處理器,就是這一發展趨勢的佐證。要充分發揮多核豐富的計算資源優勢,多核下的並行程式設計就不可避免,Linux kernel就是一典型的多核並行程式設計場景。但多核下的並行程式設計卻挑戰多多。
多核並行程式設計的挑戰
目前主流的計算機都是馮諾依曼架構,即共享記憶體的計算模型,這種過程計算模型對平行計算並不友好。下圖是一種典型的計算機硬體體系架構。
這種架構中,有如下設計特點:
·多個CPU核改善處理器的計算處理能力;
·多級cache改善CPU訪問主存的效率;
·各個CPU都有本地記憶體(NUMA(非一致性記憶體訪問)),進一步改善CPU訪問主存的效率;
·store buffer模組改善cache write由於應答延遲而造成的寫停頓問題;
·invalidate queue模組改善使無效應答的時延,把使無效命令放入queue後就立即傳送應答;
外設DMA支援直接訪問主存,改善CPU使用效率;
這些硬體體系設計特點也引入很多問題,最大的問題就是cache一致性問題和亂序執行問題。
cache一致性問題由cache一致性協議MESI解決,MESI由硬體保證,對軟體來說是透明的。MESI協議保證所有CPU對單個cache line中單個變數修改的順序保持一致,但不保證不同變數的修改在所有CPU上看到的是相同順序。這就造成了亂序。不僅如此,亂序的原因還有很多:
·store buffer引起的延遲處理,會造成亂序;
·invalidate queue引起的延遲處理,會造成亂序;
·編譯最佳化,會造成亂序;
·分支預測、多流水線等CPU硬體最佳化技術,會造成亂序;
·外設DMA,會造成資料亂序;
這種情況造成,就連簡單的++運算操作的原子性都無法保證。這些問題必須採用多核並行程式設計新的技術手段來解決。
多核並行程式設計關鍵技術
鎖技術
Linux kernel提供了多種鎖機制,如自旋鎖、訊號量、互斥量、讀寫鎖、順序鎖等。各種鎖的簡單比較如下,具體實現和使用細節這裡就不展開了,可以參考《Linux核心設計與實現》等書的相關章節。
·自旋鎖,不休眠,無程式上下文切換開銷,可以用在中斷上下文和臨界區小的場合;
·訊號量,會休眠,支援同時多個併發體進入臨界區,可以用在可能休眠或者長的臨界區的場合;
·互斥量,類似與訊號量,但只支援同時只有一個併發體進入臨界區;
·讀寫鎖,支援讀併發,寫寫/讀寫間互斥,讀會延遲寫,對讀友好,適用讀側重場合;
·順序鎖,支援讀併發,寫寫/讀寫間互斥,寫會延遲讀,對寫友好,適用寫側重場合;
鎖技術雖然能有效地提供並行執行下的競態保護,但鎖的並行可擴充套件性很差,無法充分發揮多核的效能優勢。鎖的粒度太粗會限制擴充套件性,粒度太細會導致巨大的系統開銷,而且設計難度大,容易造成死鎖。除了併發可擴充套件性差和死鎖外,鎖還會引入很多其他問題,如鎖驚群、活鎖、飢餓、不公平鎖、優先順序反轉等。不過也有一些技術手段或指導原則能解決或減輕這些問題的風險。
·按統一的順序使用鎖(鎖的層次),解決死鎖問題;
·指數後退,解決活鎖/飢餓問題;
·範圍鎖(樹狀鎖),解決鎖驚群問題;
·優先順序繼承,解決優先順序反轉問題 ;
原子技術
原子技術主要是解決cache不一致性和亂序執行對原子訪問的破壞問題。主要的原子原語有:
ACCESS_ONECE():只限制編譯器對記憶體訪問的最佳化;
barrier():只限制編譯器的亂序最佳化;
smb_wmb():寫記憶體屏障,重新整理store buffer,同時限制編譯器和CPU的亂序最佳化;
smb_rmb():讀記憶體屏障,重新整理invalidate queue,同時限制編譯器和CPU的亂序最佳化;
smb_mb():讀寫記憶體屏障,同時重新整理store buffer和invalidate queue,同時限制編譯器和CPU的亂序最佳化;
atomic_inc()/atomic_read()等:整型原子操作;
多提一句的是,atomic_inc()原語為了保證原子性,需要對cache進行重新整理,而快取行在多核體系下傳播相當耗時,其多核下的並行可擴充套件性差。
無鎖技術
上一小節中所提到的原子技術,是無鎖技術中的一種,除此之外,無鎖技術還包括RCU、Hazard pointer等。值得一提的是,這些無鎖技術都基於記憶體屏障實現的。
Hazard pointer主要用於物件的生命週期管理,類似引用計數,但比引用計數有更好的並行可擴充套件性;
RCU適用的場景很多,其可以替代:讀寫鎖、引用計數、垃圾回收器、等待事物結束等,而且有更好的並行擴充套件性。但RCU也有一些不適用的場景,如寫側重;臨界區長;臨界區內休眠等場景。
不過,所有的無鎖原語也只能解決讀端的並行可擴充套件性問題,寫端的並行可擴充套件性只能透過資料分割技術來解決。
資料分割技術
分割資料結構,減少共享資料,是解決並行可擴充套件性的根本辦法。對分割友好(即並行友好)的資料結構有:
·陣列
·雜湊表
·基樹(Radix Tree)/稀疏陣列
·跳躍列表(skip list)
使用這些便於分割的資料結構,有利於我們透過資料分割來改善並行可擴充套件性。
除了使用合適的資料結構外,合理的分割指導規則也很重要:
·讀寫分割:以讀為主的資料與以寫為主的資料分開;
·路徑分割:按獨立的程式碼執行路徑來分割資料;
·專項分割:把經常更新的資料繫結到指定的CPU/執行緒中;
·所有權分割:按CPU/執行緒個數對資料結構進行分割,把資料分割到per-cpu/per-thread中;
4種分割規則中,所有權分割是分割最徹底的。
以上這些多核並行程式設計內容基本上涵蓋了Linux kernel中所有的併發程式設計關鍵技術。當然並行程式設計還有很多其他技術沒有應用到Linux kernel中的,如無副作用的並行函數語言程式設計技術(Erlang/Go等)、訊息傳遞、MapReduce等等。
本文作者:wahaha02
原文連結:https://www.cnblogs.com/wahaha02/p/9175637.html
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31473948/viewspace-2156123/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- (轉)多核處理器的九大關鍵技術
- 分散式混合並行訓練關鍵技術解讀分散式並行
- QTP關鍵技術QT
- 分享Linux程式凍結技術Linux
- Parallel 並行技術Parallel並行
- Java技術分享之函數語言程式設計!Java函數程式設計
- Java技術分享之函數語言程式設計Java函數程式設計
- 程式設計師可以只關心技術麼?程式設計師
- 關於技術分享的思考
- oracle的Parallel 並行技術OracleParallel並行
- 直播回顧:隱私計算的關鍵技術以及行業應用技巧 | 龍蜥技術行業
- 好程式設計師web前端技術分享css盒模型程式設計師Web前端CSS模型
- 好程式設計師技術教程分享JavaScript運動框架程式設計師JavaScript框架
- UI設計培訓技術分享:配色秘籍UI
- 雲技術是軟體技術,並非硬體技術
- 大資料的關鍵技術大資料
- 好程式設計師Java培訓分享Java之反射技術程式設計師Java反射
- 好程式設計師web前端技術分享媒體查詢程式設計師Web前端
- 直播CDN排程技術關鍵挑戰與架構設計架構
- 技術方案設計的方法論及案例分享
- 技術分享| 淺談排程平臺設計
- 「程式設計師閱讀技術文章真的可以提升技術嗎?| 掘金技術徵文」程式設計師
- 技術沙龍|京東雲端到端多媒體關鍵技術揭秘
- 好程式設計師雲端計算教程分享Mysql技術知識點程式設計師MySql
- 程式設計師的技術遺產程式設計師
- 好程式設計師+爛技術=痛苦程式設計師
- 程式設計技術點滴一(Delphi)程式設計
- Battleship程式設計語言與技術BAT程式設計
- 用C語言技術進行CGI程式設計(轉)C語言程式設計
- 程式設計師如何選擇程式設計技術書?程式設計師
- 實現VR直播的關鍵技術VR
- 語音技術——關鍵詞搜尋
- Qtum量子鏈關鍵技術解讀QT
- 好程式設計師技術分享淺談JavaScript中的閉包程式設計師JavaScript
- 關於技術分享的一點感悟
- MetaForce佛薩奇2.0系統技術開發程式設計(技術示例)程式設計
- OpenAI Sora 關鍵技術詳解:揭秘時空碎片 (Spacetime Patches) 技術OpenAISora
- 關於PHP程式設計師技術職業生涯規劃PHP程式設計師