GCD 的全稱是 Grand Central Dispatch,可譯為“牛逼的中樞調度器”,GCD 是純 C 語言,提供了非常多且強大的函數。
- GCD 的優勢
- GCD是蘋果公司為多核的并行運算提出的解決方案
- GCD會自動利用更多的CPU內核(比如雙核、四核)
- GCD會自動管理線程的生命周期(創建線程、調度任務、銷毀線程)
- 程序員只需要告訴GCD想要執行什么任務,不需要編寫任何線程管理代碼
任務與隊列
在 GCD 中有兩個核心概念,分別是任務和隊列。
- 任務:用來執行什么操作
- 隊列:用來存放任務
使用 GCD 只需要兩個步驟:
- 封裝任務:
- 確定想要做的事情
- 將任務添加到隊列中:
- GCD會自動將隊列中的任務取出,放到對應的線程中執行
- 任務的取出遵循隊列的 FIFO 原則:先進先出,后進后出,即先存進去的任務優先取出執行
執行任務的兩種常用函數
-
同步函數
- 只能在當前線程中執行任務,不具備開啟新線程的能力
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
-
異步函數
- 可以在新的線程中執行任務,具備開啟新線程的能力
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
隊列的基本類型
- 并發隊列
- 可以讓多個任務并發(同時)執行(自動開啟多個線程同時執行任務)
- 并發功能只有在異步(
dispatch_async
)函數下才有效
- 串行隊列
- 讓任務一個接著一個地執行(一個任務執行完畢后,再執行下一個任務)
- 主隊列
- 凡是添加到主隊列中的任務一律放到主線程中執行
- 全局并發隊列
- 在系統中默認就存在了四種優先級的全局并發隊列
- DISPATCH_QUEUE_PRIORITY_HIGH // 高
- DISPATCH_QUEUE_PRIORITY_DEFAULT // 默認(中)
- DISPATCH_QUEUE_PRIORITY_LOW // 低
- DISPATCH_QUEUE_PRIORITY_BACKGROUND // 后臺
- 在系統中默認就存在了四種優先級的全局并發隊列
注意:同步和異步主要影響的是能不能開啟新的線程
,并發和串行主要影響的是任務的執行方式
,這里千萬不要混淆了。
GCD 的六種基本使用方式
在 iOS6.0 之前,在 GCD 中每當使用帶 creat 單詞的函數創建對象之后,都應該對其進行一次 release 操作。在 iOS6.0 之后,GCD 被納入到了 ARC 的內存管理機制,就不再關心內存問題了。
-
同步函數 + 串行隊列
- 不會開線程,所有的任務在當前線程串行執行
/** "syncSerial" 隊列的名稱,調試的時候使用 DISPATCH_QUEUE_CONCURRENT 并發隊列 DISPATCH_QUEUE_SERIAL 串行隊列 */ dispatch_queue_t queue = dispatch_queue_create("syncSerial", DISPATCH_QUEUE_SERIAL); dispatch_sync(queue, ^{ NSLog(@"--- %@", [NSThread currentThread]); });
-
同步函數 + 并發隊列
- 不會開線程,所有的任務在當前線程串行執行
dispatch_queue_t queue = dispatch_queue_create("syncConcurrent", DISPATCH_QUEUE_CONCURRENT); dispatch_sync(queue, ^{ NSLog(@"--- %@", [NSThread currentThread]); });
-
同步函數 + 主隊列
產生死鎖
- 原因:同步函數不會新開線程,必須在當前線程(主線程)執行完本次任務才能繼續向下執行,但是主隊列中的任務必須在主線程中執行,就會去調用主線程來執行任務,這樣就會形成主線程要執行任務,任務要調用主線程的情況,形成死循環,即形成死鎖。
//獲取主隊列 dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_sync(queue, ^{ NSLog(@"--- %@", [NSThread currentThread]); });
-
異步函數 + 串行隊列
- 會開一條線程,所有的任務在當前線程串行執行
dispatch_queue_t queue = dispatch_queue_create("asyncSerial", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{ NSLog(@"--- %@", [NSThread currentThread]); });
-
異步函數 + 并發隊列
- 會開多條線程(至少一條,具體由系統決定,與任務的數量無關),所有的任務并發執行
dispatch_queue_t queue = dispatch_queue_create("asyncConcurrent", DISPATCH_QUEUE_CONCURRENT); //將任務添加到隊列中 dispatch_async(queue, ^{ NSLog(@"--- %@", [NSThread currentThread]); });
-
異步函數 + 主隊列
- 不會開線程,所有的任務在主線程中串行執行
//獲取主隊列 dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_async(queue, ^{ NSLog(@"--- %@", [NSThread currentThread]); });
隊列的執行效果
并發隊列 | 手動創建的串行隊列 | 主隊列 | |
---|---|---|---|
同步( sync ) | 沒有開啟新線程,當前線程串行執行任務 | 沒有開啟新線程,當前線程串行執行任務 | 死鎖 |
異步( async ) | 開啟多條新線程,并發執行任務 | 開啟一條新線程,串行執行任務 | 沒有開啟新線程,主線程串行執行任務 |
注意:使用同步函數往當前串行隊列中添加任務,會卡住當前的串行隊列。