1. 程式人生 > >iOS多執行緒之GCD、OperationQueue 對比和實踐記錄

iOS多執行緒之GCD、OperationQueue 對比和實踐記錄

[toc] # 簡介      在計算的早期,計算機可以執行的最大工作量是由 CPU 的時鐘速度決定的。但是隨著技術的進步和處理器設計的緊湊化,熱量和其他物理約束開始限制處理器的最大時鐘速度。因此,晶片製造商尋找其他方法來提高晶片的總體效能。他們決定的解決方案是增加每個晶片上的處理器核心數量。通過增加核心的數量,一個單獨的晶片可以每秒執行更多的指令,而不用增加 CPU 的速度或改變晶片的大小或熱特性。唯一的問題是如何利用額外的核心。      應用程式使用多核的傳統方法是建立多個執行緒。與依賴執行緒不同,iOS 採用非同步設計方法來解決併發問題。通常,這項工作涉及獲取一個後臺執行緒,在該執行緒上啟動所需的任務,然後在任務完成時向呼叫方傳送通知(通常通過一個回撥函式)。      iOS 提供了一些技術,允許您非同步執行任何任務,而無需自己管理執行緒。非同步啟動任務的技術之一是 Grand Central Dispatch (GCD)。這種技術採用執行緒管理程式碼,並將該程式碼移動到系統級別。您所要做的就是定義要執行的任務,並將它們新增到適當的分派佇列中。GCD 負責建立所需的執行緒,並安排任務在這些執行緒上執行。由於執行緒管理現在是系統的一部分,GCD 提供了任務管理和執行的整體方法,比傳統執行緒提供了更高的效率。      OperationQueue(操作佇列,api 類名為 NSOperationQueue )是 Objective-C 物件,是對 GCD 的封裝。其作用非常類似於分派佇列。您定義要執行的任務,然後將它們新增到 OperationQueue 中, OperationQueue 處理這些任務的排程和執行。與 GCD 一樣, OperationQueue 為您處理所有執行緒管理,確保在系統上儘可能快速有效地執行任務。 # GCD、OperationQueue 對比 ## 核心理念 * GCD的核心概念:將 任務(block) 新增到佇列,並且指定執行任務的函式。 * NSOperation 的核心概念:把 操作(非同步) 新增到 佇列。 ## 區別 * GCD: * 將任務(block)新增到佇列(序列/併發/主佇列),並且指定任務執行的函式(同步/非同步) * GCD是底層的C語言構成的API * iOS 4.0 推出的,針對多核處理器的併發技術 * 在佇列中執行的是由 block 構成的任務,這是一個輕量級的資料結構 * 要停止已經加入 queue 的 block 需要寫複雜的程式碼 * 需要通過 Barrier(dispatch_barrier_async)或者同步任務設定任務之間的依賴關係 * 只能設定佇列的優先順序 * 高階功能: dispatch_once_t(一次性執行, 多執行緒安全); dispatch_after(延遲); dispatch_group(排程組); dispatch_semaphore(訊號量); dispatch_apply(優化順序不敏感大體量for迴圈); * OperationQueue: * OC 框架,更加面向物件,是對 GCD 的封裝。 * iOS 2.0 推出的,蘋果推出 GCD 之後,對 NSOperation 的底層進行了全部重寫。 * 可以設定佇列中每一個操作的 QOS() 佇列的整體 QOS * 操作相關 Operation作為一個物件,為我們提供了更多的選擇: 任務依賴(addDependency),可以跨佇列設定操作的依賴關係; 在佇列中的優先順序(queuePriority) 服務質量(qualityOfService, iOS8+); 完成回撥(void (^completionBlock)(void) * 佇列相關 服務質量(qualityOfService, iOS8+); 最大併發運算元(maxConcurrentOperationCount),GCD 不易實現; 暫停/繼續(suspended); 取消所有操作(cancelAllOperations); KVO 監聽佇列任務執行進度(progress, iOS13+);      接下來通過文字,結合實踐程式碼(**工程連結在文末**)和執行效果 gif 圖對部分功能進行分析。 # GCD ## 佇列 ### 序列佇列(Serial Queues)      序列佇列中的任務按順序執行;但是不同序列佇列間沒有任何約束; 多個序列佇列同時執行時,不同佇列中任務執行是併發的效果。比如:火車站買票可以有多個賣票口,但是每個排的隊都是序列佇列,整體併發,單線序列。      注意防坑:序列佇列建立的位置。比如下面程式碼示例中:在for迴圈內部建立時,每個迴圈都是建立一個新的序列佇列,裡面只裝一個任務,多個序列佇列,結果整體上是併發的效果。想要序列效果,必須在for迴圈外部建立序列佇列。      序列佇列適合管理共享資源。保證了順序訪問,杜絕了資源競爭。       程式碼示例: ```swift private func serialExcuteByGCD(){ let lArr : [UIImageView] = [imageView1, imageView2, imageView3, imageView4] //序列佇列,非同步執行時,只開一個子執行緒 let serialQ = DispatchQueue.init(label: "com.companyName.serial.downImage") for