GCD 多線程技術
Grand Central Dispatch(GCD)是異步執行任務的技術之一。一般將應用程序中記述的線程管理用
的代碼在系統級中實現。開發者只需要定義想執行的任務並追加到適當的Dispatch Queue中,DCD就能生成
必要的線程並計劃執行任務。由於線程管理是作為系統的一部分來實現的,因此可以統一管理,也可以執行任務,
這樣就比以前的線程更有效率。
GCD API
1. Dispatch Queue 隊列
隊列有兩種類型:
Serial Dispatch Queue 串行隊列,使用一個線程,按照追加的順序(先進先出FIFO)執行處理。多個串行隊列之間是並行處理的。
Concurrent Dispatch Queue 並行隊列,使用多個線程,並發處理
2.diapatch_queue_create
創建 Serial Queue:
dispatch_queue_t mySerailQueue = dispatch_queue_create("com.r.dispatchSerailQueue", DISPATCH_QUEUE_SERIAL); dispatch_queue_t myConcurrentQueue = dispatch_queue_create("com.r.dispatchConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
第一個參數是指定 Serial dispatch queue 的名稱。該名稱在Xcode和Instruments的調試器中作為Dispatch Queue名稱.
第二個參數是生成Dispatch Queue的類型,如果是NULL 或者 DISPATCH_QUEUE_SERIAL生成串行隊列,
指定為DISPATCH_QUEUE_CONCURRENT生成並發隊列.
3.Main Dispatch Queue/Global Dispatch Queue
獲取系統標準提供的Dispatch Queue。
Main Dispatch Queue是在主線程執行的dispatch queue, Main Dispatch Queue是一個Serail Dispatch Queue。追加到Main Dispatch Queue的處理在主線程的RunLoop中執行。一般將用戶界面更新等必需要在主線程中執行的處理追加到Main Dispatch Queue中。
Global Dispatch Queue是所有應用程序都能過使用的Concurrent Dispatch Queue。沒有必要通過dispatch_queue_create函數逐個創建Concurrent Dispatch Queue,只要獲取Global Dispatch Queue使用即可。Global Dispatch Queue有四個優先級
名稱 | Dispatch Queue的種類 | 說明 |
---|---|---|
Main Dispatch Queue | Serial Dispatch Queue | 主線程執行 |
Global Dispatch Queue(High Priority) | Concurrent Dispatch queue | 執行優先級:高(最高) |
Global Dispatch Queue(Default Priority) | Concurrent Dispatch queue | 執行優先級:默認 |
Global Dispatch Queue(Low Priority) | Concurrent Dispatch queue | 執行優先級:低 |
Global Dispatch Queue(Background Priority) | Concurrent Dispatch queue | 執行優先級:後臺 |
獲取Dispatch Queue方法:
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue(); dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
使用Main Dispatch Queue 和 Global Dispatch Queue
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ /** * 可並行處理的任務TODO */ dispatch_async(dispatch_get_main_queue(), ^{ /** * 主線程執行 */ }); });
4. dispatch_after
dispatch_after表示在指定的時間之後追加處理到Dispatch Queue。並不是指定時間後執行處理。
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC); dispatch_after(time, dispatch_get_main_queue(), ^{ NSLog(@"等待3秒後執行"); });
雖然在有嚴格時間到要求下使用時會出現問題,但在大致延遲執行處理時,該函數還是有效的。
5.dispatch_suspend/dispatch_resume
當追加大量處理到Dispatch Queue時,在追加處理到過程中,有時希望不執行已追加的處理。在這種情況下只要掛起Dispatch Queue即可。
dispatch_suspend 函數掛起指定的Dispatch Queue
dispatch_resume 函數恢復指定的Dispatch Queue
這些函數對已經執行的處理沒有影響,掛起後,追加到Dispatch Queue中處理在此之後暫停執行,而恢復使得這些處理繼續執行。
6.Dispatch Group
在追加到Dispatch Queue中的多個處理全部結束後想執行結束處理.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ for (int i=0; i<2000; i++) { NSLog(@"111111"); } }); dispatch_group_async(group, queue, ^{ for (int i=0; i<2000; i++) { NSLog(@"2222222"); } }); dispatch_group_async(group, queue, ^{ for (int i=0; i<2000; i++) { NSLog(@"33333"); } }); //最後執行4444 dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"44444"); }); NSLog(@"555555");
7. dispatch_barrier_async
dispatch_async(queue, ^{ //讀文件 }); dispatch_async(queue, ^{ //讀文件 }); //使用dispatch_barrier_async避免數據競爭 dispatch_barrier_async(queue, ^{ //寫文件 }); dispatch_async(queue, ^{ //讀文件 }); dispatch_async(queue, ^{ //讀文件 });
一個dispatch barrier 允許在一個並發隊列中創建一個同步點。當在並發隊列中遇到一個barrier, 他會延遲執行barrier的block,
等待所有在barrier之前提交的blocks執行結束。 這時,barrier block自己開始執行。 之後, 隊列繼續正常的執行操作。
調用這個函數總是在barrier block被提交之後立即返回,不會等到block被執行。當barrier block到並發隊列的最前端,
他不會立即執行。相反,隊列會等到所有當前正在執行的blocks結束執行。到這時,barrier才開始自己執行。
所有在barrier block之後提交的blocks會等到barrier block結束之後才執行。
這裏指定的並發隊列應該是自己通過dispatch_queue_create函數創建的。
如果你傳的是一個串行隊列或者全局並發隊列,這個函數等同於dispatch_async函數。
8.dispatch_apply
dispatch_apply函數是dispatch_sync函數和Dispatch Group的關聯API。
該函數按指定的次數將指定的Block追加到Dispatch Queue中,並等待全部處理執行結束。
1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 2 dispatch_apply(10, queue, ^(size_t index) { 3 NSLog(@"%zu", index);//並行 4 }); 5 //最後執行 6 NSLog(@"11");
9. Dispatch Semaphore
信號量:就是一種可用來控制訪問資源的數量的標識,設定了一個信號量,在線程訪問之前,加上信號量的處理,則可告知系統按照我們指定的信號量數量來執行多個線程。
1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 2 3 /** 4 * 生成Dispatch Semaphore 5 * Dispatch Semaphore 的計數初始值設定為1 6 * 保證可訪問NSMutableArray類對象的線程同時只有一個 7 */ 8 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); 9 NSMutableArray *array = [[NSMutableArray alloc] init]; 10 11 for (int i=0; i<10000; i++) { 12 dispatch_async(queue, ^{ 13 /** 14 * 等待Dispatch Semaphore 15 一直等待,直到Dispatch Semaphore 的計數的值達到大於等於1 16 */ 17 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 18 19 /** 20 * 由於Dispatch Semaphore 的計數達到大於等於1 21 所以Dispatch Semaphore 的計數值減去1 22 dispatch_semaphore_wait函數執行返回 23 24 即執行到此時Dispatch Semaphore的計數值恒為00 25 26 由於可訪問NSMutableArray類對象的線程數只有1個 27 因此可安全的進行更新 28 */ 29 [array addObject:[NSNumber numberWithInt:i]]; 30 31 /** 32 * 排他控制處理結束 33 所以通過dispatch_semaphore_signal函數 34 將DispatchSemaphore的計數值加1 35 如果有通過dispatch_semaphore_wait函數 36 等待Dispatch Semaphore的計數值增加的線程 37 就由最先等待的線程執行。 38 */ 39 dispatch_semaphore_signal(semaphore); 40 }); 41 }
GCD 多線程技術