一. GCD的核心概念
-
什么是CGD
- GCD, 全稱Grand Central Dispatch, 又稱中樞調度器
- 他是Apple公司推出的, 使用純C語言編寫的(意味著性能的高效), 為多核的并行運算創建的牛X產物
- GCD會自動的利用多核的CPU, 達到更快速的調度線程, 更搞笑的執行任務
- CGD會自動的管理線程的聲明周期, 如創建線程/調度任務/銷毀線程
-
核心概念
- 任務: 線程需要去執行的操作, 方法, 代碼段
- 隊列: 用于存放任務的容器
- 任務添加并存放在隊列中, 然后將隊列中的任務, 根據函數調用的不同, 自發的分配給不同的線程去執行
- 并且任務的取出, 遵循隊列的FIFO原則: 先進先出, 后進后出
-
同步和異步
-
同步:
dispatch_sync( queue隊列, block任務 )
- 同步: 如果當前線程的任務沒有執行完畢, 隊列中的其他任務就會處于等待執行的狀態
- 同步函數: 同步函數不具備開啟新線程的能力, 他只能在當前的線程中去執行任務(在哪個線程中執行這個函數, 就在那個線程執行所有的任務)
-
異步:
dispatch_async( queue隊列, block任務 )
- 異步: 當前線程中的任務沒有執行完畢, 其他的線程也可以被調度去執行任務
- 異步函數: 具備開啟線程的能力, 可以在新的線程中執行任務
-
二. GCD中的隊列
-
并發和串行的概念
- 并發: 可讓多個任務并發(同時)執行的隊列, 他自動開啟多個線程去執行任務
- 并發功能只有在異步函數(dispatch_async)下才會生效
- 串行: 讓隊列中的任務, 按順序一個個地執行, 即一個任務執行完畢后, 在調度執行下一個任務
- 并發: 可讓多個任務并發(同時)執行的隊列, 他自動開啟多個線程去執行任務
-
并發隊列
創建一個并發隊列:
dipatch_queue_t queue = dispatch_queue_create("隊列名稱", DISPATCH_QUEUE_CONCURRENT)
-
獲取全局并發隊列
dispatch_queue_t queueG = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 第一個參數: 隊列的優先級, 分為High/Low/Default/Background 第二個參數: 暫未采用的參數, 始終傳入0
GCD內部開啟多少條線程, 是根據系統的當前情況自行決定的, 并不是根據任務的數量去開啟對應的線程
-
串行隊列
- 創建一個串行隊列:
dispatch_queue_t queue = dispatch_queue_create("隊列名稱", DISPATCH_QUEUE_SERIAL)
- 獲取主隊列
- 凡是放在主隊列中的任務, 都必須在主線程中執行
- 主隊列是默認存在的隊列, 并不是手動創建的
- 主隊列在調度任務之前, 會檢查主線程的狀態, 如果主線程當前正在執行任務, 那么主隊列就會停止調度隊列中的任務
- 創建一個串行隊列:
三. 線程. 隊列和函數之間的組合(重要)
-
在并發隊列中, 使用異步函數調度任務
任務的執行, 會開啟新的線程
系統自行決定開啟的線程的數量
-
任務會被分配到不同線程中并發執行
// 1. 并發隊列,異步函數,每個異步函數開啟了新的線程,并發執行任務 - (void)conAsync { // 1. 創建隊列(并發隊列) dispatch_queue_t queue = dispatch_queue_create("隊列名稱", DISPATCH_QUEUE_CONCURRENT); // 2. 使用函數封裝任務,并把任務添加到隊列中(異步) dispatch_async(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在并發隊列中, 使用同步函數調度任務
同步函數執行的任務, 并不會開啟新的線程, 都在主線程中執行
-
所有的任務串行執行
// 2. 并發隊列,同步函數,不會開啟新的線程,任務按照順序串行執行 - (void)conSync { // 1. 創建普通的并發隊列, 效果與全局并發隊列相同 // dispatch_queue_t queue = dispatch_queue_create("adsfa", DISPATCH_QUEUE_CONCURRENT); // 1.1 創建全局并發隊列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); // 2. 封裝任務,并添加到隊列中(同步) dispatch_sync(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在串行隊列中, 使用異步函數調度任務
異步函數具備開啟子線程的能力, 因此會開啟一條線程, 但是由于是串行隊列, 因此只會開啟一條新線程
-
所有的任務都在這個新線程中串行執行任務
// 3. 串行隊列,異步函數,開啟了一條子線程,隊列中的任務是串行執行的 - (void)serAsync { // 1. 創建串行隊列 dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_SERIAL); // 2. 使用異步函數封裝任務 dispatch_async(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在串行隊列中, 使用同步函數執行任務
同步函數不具備開啟線程的能力, 因此所有任務是在主線程中執行的
-
串行隊列中的任務, 是串行執行的
- (void)serSync { // 1. 創建串行隊列 dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_SERIAL); // 2. 使用同步函數封裝任務 dispatch_sync(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在主隊列中, 使用異步函數調度任務
異步函數雖然具備開啟線程的能力, 但是由于主隊列中的任務只能在主線程中執行, 因此并不會開啟新的線程
-
主隊列也屬于串行隊列, 因此任務串行執行
- (void)mainAsync { // 1. 創建主隊列 dispatch_queue_t queue = dispatch_get_main_queue(); // 2. 使用異步添加任務 dispatch_async(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在主隊列中, 使用同步函數調度任務重中之重, 常考問題!!!
主隊列中的任務都會放在主線程中執行
主隊列的特性: 如果主線程目前有任務在處理, 處于忙碌狀態, 那么主隊列就會暫停調度任務
同步函數不具備開啟新線程的能力, 因此同步函數的任務也只能在主線程中處理
當第一個同步函數, 放入主線程準備執行的時候, 這時主線程就會進入工作狀態, 并且進入忙碌狀態
-
這時主隊列察覺到主線程正處于忙碌, 因此就會停止調度任務, 這時任務的調度停止了, 第一個進入主隊列的同步函數也就停止了執行, 此時, 就會出現死鎖狀態, 變現為程序的死機
- (void)mainSync { // 1. 獲取主隊列 dispatch_queue_t queue = dispatch_get_main_queue(); NSLog(@"123"); // 2. 使用同步添加任務 dispatch_sync(queue, ^{ // 當開始處理第一個任務的時候, 主線程就已經掛掉了 NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }