原文連接 http://www.objc.io/issue-2/concurrency-apis-and-pitfalls.htmlhtml
已經有中文版了: http://beyondvincent.com/blog/2013/07/16/104/ 算法
原本想本身一邊翻譯一遍看的,結果發現量有點大,還要調整配圖,麻煩,就算了。就記下要點吧。編程
1. 併發包含單核的分時系統和真正的多核系統api
2. OS X/iOS 包含一組API: GCD, NSOperationQueue, pthread/NSThread (NSRunLoop只是很是相關)安全
3. 可使用Instruments的 CPU strategy view來觀察CPU cores的利用狀況網絡
4. pthread兼容POSIX, NSThread是pthread的外包類, 寫起來相對複雜,不推薦直接使用併發
5. 若是本身也使用pthread,所用的庫的實現也用了pthread,那麼和可能來個乘法效應,好比庫探測出硬件有4核,因而生成4個線程;每一個線程裏面插入了本身的幹活代碼,這裏也分配了4個線程..等等。冗餘的線程是有內存和內核開銷的。函數
6. 基於隊列的API, 建立一個線程池來控制工具
6.1 GCD oop
直接考慮幹活的block代碼,而非關注線程自己。具體參考圖。
主線程 --- 主隊列(串行隊列)
GCD線程池 --- 高中低以及背景優先級隊列(以默認的中優先級隊列爲例,能夠設置串行隊列,也能夠設置並行隊列,後者再塞入串行隊列)
GCD很底層也很方便,但仍然要當心併發編程的各類警告和陷阱(見後文)
6.2 OperationQueue
基於GCD之上,足夠的彈性而且這種封裝也避免了直接使用GCD容易產生的一些問題
NSOperationQueue分兩種,主線程上跑的main queue和別的線程上跑的自定義queue,工做任務被封裝成NSOperation,能夠重寫NSOperation的main/start/finished
NSOperationQueue也能夠直接加入block。
他們很是適合於調試: 重載description函數能夠輸入內部的各類細節狀態
其餘有用的參數: maxConcurrentOperationCount 設置爲1就是串行的隊列,減小了任務之間的衝突。
還能夠在NSOperation之間 addDependency,控制啓動順序(以及更重要的,是否是必須等運行完畢了再啓動!)
小結: 相比直接使用GCD,代價輕微,很是實用,最優先的工具。
7 Run Loops 主線程有個默認的NSRunloop, 在操做時自動切換模式(優先處理輸入)。給其餘線程的Runloop作設置時要加一個source,不然直接退出。具體例子見本系列其餘文章
8 併發編程的挑戰(通用知識,能夠自行找相關書籍看,好比深刻理解計算機系統什麼的)
8.1 資源分享 資源能夠是一個對象,通用內存,網絡設備,文件等等。容易產生hazard, 好比A、B線程都給某個值爲17的變量增長1,A增長以後還沒有寫回時,B讀取後再增長,因而兩次寫入都是18,結果是18而不是期待的19,這就是race condition 競態條件,因爲現代cpu的亂序執行可能問題更加複雜。
8.2 爲了解決race condition,引入mutal exclusion,資源鎖,鎖定原子級(atomic)操做。鎖自己還要支持亂序執行下的正確性,因而須要插入memory barrier保證cpu語意正確,因此自己開銷就比較大。 鎖的設計也有多種,有的是當沒有鎖上時,開銷很小但一旦資源有鎖,開銷就很大;有些則是在基礎狀況下開銷更高一些,可是在資源有鎖的狀況下的開銷會相對好一些。若是幾個線程在競爭使用某個資源,那麼效率可能至關低。
8.3 鎖還帶來了另外一個嚴重問題: Dead lock 死鎖。舉例: 線程A 拿到資源1,等着拿到資源2後繼續幹活;線程B拿到資源2,等着拿到資源1繼續幹活。因而你們一直在等待。因此儘量保持簡單,避免死鎖的出現。系列的其餘文章會詳述這些問題。
8.4 飢餓/Starvation 通常狀況下,對於一個資源能夠有多個只讀的鎖和一個寫的鎖。有隻讀的鎖的狀況下能夠繼續加只讀鎖,結果致使寫的鎖一直在等待全部的只讀鎖退出後再去寫。 readers-writers problem,解決辦法是writers preference / read-copy-update 算法
8.5 優先級反轉 Priority Inversion 高中低三個線程。低優先級的線程鎖住了高優先級的線程須要的資源,這時候高優先級的線程鎖不上資源因而等着;低優先級的線程因爲被中優先級的線程壓制,無法得到運行時間釋放資源。結論是別用不一樣的優先級啦,一不當心就優先級反轉了。NASA在火星探路者上的遭遇代表,即便是頗有經驗的工程師也可能碰到這種問題。
9 總結 安全模式之一: 主線程丟出去數據,用操做隊列在後臺作實際的工做,作完後把結果回報給主線程的主隊列main queue。 這樣就避免了各類鎖,減小錯誤的可能性。
2013.09.17