1、GCD簡介
-
GCD 是 Grand Central Dispatch(譯為 “中樞調度器”)的簡稱,它是基於 C 語言編寫的,是蘋果公司為多核的並行運算提出的解決方案。
-
GCD 在工作時會自動利用更多的處理器核心,以充分利用更強大的機器。
-
如果使用 GCD,完全由系統管理線程,我們不需要編寫線程代碼,只需定義想要執行的任務,然后添加到適當的調度隊列(dispatch queue),GCD 會負責創建線程和調度你的任務。
-
它首次發布在 Mac OS X 10.6 ,iOS 4 上。在 iOS 所有實現多線程的方案中,GCD 應該是最有魅力的,GCD 是一個替代諸如 NSThread, NSOperationQueue,NSInvocationOperation 等技術的很高效和強大的技術。
-
1.1 工作原理:
- 將長期運行的任務拆分成多個工作單元,並將這些單元添加到 dispath queue 中,系統會為我們管理這些 dispath queue,根據可用的處理資源,安排他們在任何可用的處理器核心上執行任務。
- 我們不需要直接啟動和管理后台線程。
- 一個任務可以是一個函數(function)或者是一個 block。
- GCD 的底層依然是用線程實現,不過這樣可以讓程序員不用關注實現的細節。
- 將任務添加到隊列,並且指定執行任務的函數,執行任務。任務使用 block 封裝,任務的 block 沒有參數也沒有返回值。
-
1.2 執行任務的函數:
- 異步 dispatch_async
- 不用等待當前語句執行完畢,就可以執行下一條語句。
- 會開啟線程執行 block 的任務。
- 異步是多線程的代名詞。
- 同步 dispatch_sync
- 必須等待當前語句執行完畢,才會執行下一條語句。
- 不會開啟線程。
- 在當前線程執行 block 的任務。
- 同步任務的作用:同步任務,可以讓其他異步執行的任務,"依賴" 某一個同步任務。例如:在用戶登錄之后,再異步下載文件!
- 異步 dispatch_async
-
1.3 任務調度隊列:
- GCD 中的 FIFO 隊列稱為 dispatch queue(調度隊列)。系統提供了許多預定義的 dispatch queue,包括可以保證始終在主線程上執行工作的 dispatch queue。
- 也可以創建自己的 dispatch queue,而且可以創建任意多個。GCD 的 dispatch queue 嚴格遵循 FIFO(先進先出) 原則,添加到 dispatch queue 的工作單元將始終按照加入 dispatch queue 的順序啟動。
- dispatch queue 按先進先出的順序,串行或並發地調度任務在線程上實行。
- dispatch queue 分為下面三種:
-
Serial:
- 串行隊列,又稱為 private dispatch queues,一次只能 "調度" 一個任務, 當前任務完成才開始出列並啟動下一個任務。Serial queue 通常用於同步訪問特定的資源或數據。當你創建多個 Serial queue 時,雖然它們各自是同步執行的,但 Serial queue 與 Serial queue 之間是並發執行的。
-
Concurrent:
- 並發隊列,又稱為 global dispatch queues,一次可以 "調度" 多個任務,盡可能多地啟動任務並發執行,任務執行完成的順序是隨機的。
- 系統給每一個應用程序提供了三個 concurrent dispatch queues。這三個並發調度隊列是全局的,它們只有優先級的不同。因為是全局的,我們不需要去創建。我們只需要通過使用函數 dispath_get_global_queue 去得到隊列。
-
Main dispatch queue:
- 主隊列,它是全局可用的 serial queue,專門用來在主線程上調度任務的隊列。不會開啟線程,主隊列異步執行時如果主線程上正在有代碼執行,就不會調度隊列中的任務,等待主線程空閑之后再調度任務。主線程中主隊列同步執行時,主隊列和主線程相互等待會造成死鎖。
-
-
1.4 各種隊列的執行效果:
Type 全局並發隊列 手動創建串行隊列 主隊列 同步 (sync) 沒有開啟新線程 沒有開啟新線程 沒有開啟新線程 ~ 串行執行任務 串行執行任務 串行執行任務 異步 (async) 有開啟新線程 有開啟新線程 沒有開啟新線程 ~ 並發執行任務 串行執行任務 串行執行任務 - 開不開線程由執行任務的函數決定:
- 異步開,異步是多線程的代名詞。
- 同步不開。
- 開幾條線程由隊列決定:
- 串行隊列開一條線程。
- 並發隊列開多條線程。
- 主隊列不會開啟線程。
- 開不開線程由執行任務的函數決定:
-
1.5 隊列的選擇:
- 多線程的目的:將耗時的操作放在后台執行!
- 串行隊列,只開一條線程,所有任務順序執行
- 如果任務有先后執行順序的要求。
- 效率低 -> 執行慢 -> "省電"。
- 有的時候,用戶其實不希望太快!例如使用 3G 流量,"省錢"。
- 並發隊列,會開啟多條線程,所有任務不按照順序執行
- 如果任務沒有先后執行順序的要求。
- 效率高 -> 執行快 -> "費電"。
- WIFI,包月。
- 實際開發中
- WIFI 線程數 6 條。
- 3G / 4G 移動開發的時候,2~3 條,再多會費電費錢。
-
1.6 全局隊列 & 並發隊列的區別:
-
1)全局隊列:
- 沒有名稱。
- 無論 MRC & ARC 都不需要考慮釋放。
- 日常開發中,建議使用 "全局隊列"。
-
2)並發隊列:
- 有名字,和 NSThread 的 name 屬性作用類似。
- 如果在 MRC 開發時,需要使用 dispatch_release(q); 釋放相應的對象。
- 開發第三方框架時,建議使用並發隊列。
-
-
1.7 GCD & NSThread 對比:
- GCD 所有的代碼寫在一起的,讓代碼更加簡單,易於閱讀和維護。
- NSThread 通過 @selector 指定要執行的方法,代碼分散。
- GCD 通過 block 指定要執行的代碼,代碼集中。
- 使用 GCD 不需要管理線程的創建/銷毀/復用的過程。程序員不用關心線程的生命周期。
- NSThread 需要自己創建線程對象,並且指定 selector 方法,然后 start。
- GCD 只需要將任務添加給隊列,並且指定執行的函數
- 如果要開多個線程 NSThread 必須實例化多個線程對象。
- NSThread 靠 NSObject 的分類方法實現的線程間通訊,GCD 靠 block。