說GCD之前先來認識下,下面幾個術語。
同步 (Synchronous)
在當前線程中執行任務,不具備開啟新線程的能力
提交的任務在執行完成后才會返回
同步函數: dispatch_sync()異步 (Asynchronous)
在新線程中執行任務,具備開啟新線程的能力
提交的任務立刻返回,在后臺隊列中執行
異步函數: dispatch_async()串行 (Serial)
一個任務執行完畢后,再執行下一個任務并發 (Concurrent)
多個任務同時執行(自動開啟多個線程),只有在異步函數下才有效
描述 | 說明 |
---|---|
queue | 隊列 |
main | 主隊列 |
global | 全局隊列 |
dispatch_queue_t | 描述隊列 |
dispatch_block_t | 描述任務 |
dispatch_once_t | 描述一次性 |
dispatch_time_t | 描述時間 |
dispatch_group_t | 描述隊列組 |
dispatch_semaphore_t | 描述信號量 |
函數 | 說明 |
---|---|
dispatch_sync() | 同步執行 |
dispatch_async() | 異步執行 |
dispatch_after() | 延時執行 |
dispatch_once() | 一次性執行 |
dispatch_apply() | 提交隊列 |
dispatch_queue_create() | 創建隊列 |
dispatch_group_create() | 創建隊列組 |
dispatch_group_async() | 提交任務到隊列組 |
dispatch_group_enter() / dispatch_group_leave() | 將隊列組中的任務未執行完畢的任務數目加減1(兩個函數要配合使用) |
dispatch_group_notify() | 監聽隊列組執行完畢 |
dispatch_group_wait() | 設置等待時間(返回 0成功,1失敗) |
注意:
1.所有的執行都放到隊列中(queue),隊列的特點是FIFO(先提交的先執行)
2.必須在主線程訪問 UIKit 的類
3.并發隊列只在異步函數下才有效
基本使用
//基本使用
NSLog(@"當前線程 %@", [NSThread currentThread]);
//獲取主隊列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//獲取全局并發隊列
dispatch_queue_t otherQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//同步函數(在當前線程中執行,不具備開啟新線程的能力)
dispatch_sync(otherQueue, ^{
NSLog(@"同步 %@", [NSThread currentThread]);
});
//異步函數(在另一條線程中執行,具備開啟新線程的能力)
dispatch_async(otherQueue, ^{
NSLog(@"異步 %@", [NSThread currentThread]);
});
從輸出結果可以看出來異步具備開啟線程的能力,而清補不具備。
延時執行 dispatch_after()
dispatch_after()延遲一段時間把一項任務提交到隊列中執行,返回之后就不能取消
常用來在在主隊列上延遲執行一項任務
NSLog(@"當前線程 %@", [NSThread currentThread]);
//GCD 延時調用(主線程)(主隊列)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"GCD 延時(主線程) %@", [NSThread currentThread]);
});
//GCD延時調用 (其他線程) (全局并發隊列)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"GCD 延時(其他線程) %@", [NSThread currentThread]);
});
一次性執行 dispatch_once()
整個程序運行中,只會執行一次 (默認線程是安全的)
dispatch_once() 以線程安全的方式執行且僅執行其代碼塊一次
for (NSInteger i = 0; i < 10; i++) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"GCD一次性執行(默認線程是安全的)");
});
通常我們會利用 dispatch_once() 來創建單例。
+ (instancetype)sharedManager {
static PhotoManager *sharedPhotoManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPhotoManager = [[PhotoManager alloc] init];
});
return sharedPhotoManager;
}
提交 dispatch_apply()
把一項任務提交到隊列中多次執行,具體是并行執行還是串行執行由隊列本身決定
dispatch_apply不會立刻返回,在執行完畢后才會返回,是同步的調用。
隊列
任務1,任務2依次執行,所有任務都執行成功后回到主線程
(效率不高)
NSLog(@"當前線程 %@", [NSThread currentThread]);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//全局并發隊列
for (NSInteger i = 0; i < 10; i++) {
NSLog(@"任務1 %@ %ld", [NSThread currentThread], i);
}
for (NSInteger i = 0; i < 10; i++) {
NSLog(@"任務2 %@ %ld", [NSThread currentThread], i);
}
dispatch_async(dispatch_get_main_queue(), ^{
//主隊列
NSLog(@"主線程執行(刷新UI)%@", [NSThread currentThread]);
});
});
隊列組
任務1,任務2同時執行,所有任務都執行成功后回到主線程
(效率高)
NSLog(@"當前線程 %@", [NSThread currentThread]);
//創建一個隊列組
dispatch_group_t group = dispatch_group_create();
//開啟任務1
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (NSInteger i = 0; i < 10; i++) {
NSLog(@"任務1 %@ %ld", [NSThread currentThread], i);
}
});
//開啟任務2
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (NSInteger i = 0; i < 10; i++) {
NSLog(@"任務2 %@ %ld", [NSThread currentThread], i);
}
});
//所有任務執行完畢
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"主線程(刷新UI) %@", [NSThread currentThread]);
});
串行與并發
- 串行隊列
一個任務執行完畢后,再執行下一個任務
主隊列是GCD自帶的一種特殊的串行隊列,放在主隊列中的任務,都會放到主線程中執行。
//(1)使用dispatch_queue_create函數創建串行隊列
//參數1: 隊列名稱
//參數2: 隊列屬性 (一般用NULL)
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
//(2)使用主隊列(跟主線程相關聯的隊列)
dispatch_queue_t serialMainQueue = dispatch_get_main_queue();
- 并發隊列
多個任務并發執行(自動開啟多個線程同時執行任務)
并發功能只有在異步(dispatch_async)函數下才有效!!!
GCD默認已經提供了全局的并發隊列,供整個應用使用,不需要手動創建。
并發隊列優先級 | 快捷值 | 優先級 |
---|---|---|
DISPATCH_QUEUE_PRIORITY_HIGH | 2 | 高 |
DISPATCH_QUEUE_PRIORITY_DEFAULT | 0 | 中(默認) |
DISPATCH_QUEUE_PRIORITY_LOW | (-2) | 低 |
DISPATCH_QUEUE_PRIORITY_BACKGROUND | INT16_MIN | 后臺 |
//(1)使用dispatch_get_global_queue函數獲得全局的并發隊列
//參數1: 優先級
//參數2: 暫時無用參數 (傳0)
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- 異步函數_并發隊列
(開啟新線程,并發執行任務
NSLog(@"當前線程 %@", [NSThread currentThread]);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務1 %@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務2 %@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務3 %@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務4 %@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務5 %@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務6 %@", [NSThread currentThread]);
});
- 異步函數_串行隊列
(開啟新線程,串行執行任務)
NSLog(@"當前線程 %@", [NSThread currentThread]);
//創建串行隊列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
dispatch_async(serialQueue, ^{
NSLog(@"任務1 %@", [NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"任務2 %@", [NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"任務3 %@", [NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"任務4 %@", [NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"任務5 %@", [NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"任務6 %@", [NSThread currentThread]);
});
- 同步函數_并發隊列
(不會開啟新線程,并發執行任務失效!)
NSLog(@"當前線程 %@", [NSThread currentThread]);
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任務1 %@", [NSThread currentThread]);
});
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任務2 %@", [NSThread currentThread]);
});
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任務3 %@", [NSThread currentThread]);
});
- 同步函數_串行隊列
(不會開啟新線程,串行執行任務)
NSLog(@"當前線程 %@", [NSThread currentThread]);
//創建串行隊列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
dispatch_sync(serialQueue, ^{
NSLog(@"任務1 %@", [NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"任務2 %@", [NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"任務3 %@", [NSThread currentThread]);
});