本文來(lái)自尚妝iOS團(tuán)隊(duì)嘉文
發(fā)表于尚妝github博客操禀,歡迎訂閱厂庇!
GCD介紹
Grand Central Dispatch (GCD)是Apple開(kāi)發(fā)的一個(gè)多核編程的解決方法
基于C語(yǔ)言觉啊,提供了非常多強(qiáng)大的函數(shù)
術(shù)語(yǔ)
同步 (Synchronous)
在當(dāng)前線程中執(zhí)行任務(wù)嘉抒,不具備開(kāi)啟新線程的能力
提交的任務(wù)在執(zhí)行完成后才會(huì)返回
同步函數(shù): dispatch_sync()異步 (Asynchronous)
在新線程中執(zhí)行任務(wù)姿鸿,具備開(kāi)啟新線程的能力
提交的任務(wù)立刻返回殖卑,在后臺(tái)隊(duì)列中執(zhí)行
異步函數(shù): dispatch_async()串行 (Serial)
一個(gè)任務(wù)執(zhí)行完畢后站削,再執(zhí)行下一個(gè)任務(wù)
并發(fā) (Concurrent)
多個(gè)任務(wù)同時(shí)執(zhí)行(自動(dòng)開(kāi)啟多個(gè)線程),
只有在異步函數(shù)下才有效
描述 | 說(shuō)明 |
---|---|
queue | 隊(duì)列 |
main | 主隊(duì)列 |
global | 全局隊(duì)列 |
dispatch_queue_t | 描述隊(duì)列 |
dispatch_block_t | 描述任務(wù) |
dispatch_once_t | 描述一次性 |
dispatch_time_t | 描述時(shí)間 |
dispatch_group_t | 描述隊(duì)列組 |
dispatch_semaphore_t | 描述信號(hào)量 |
函數(shù) | 說(shuō)明 |
---|---|
dispatch_sync() | 同步執(zhí)行 |
dispatch_async() | 異步執(zhí)行 |
dispatch_after() | 延時(shí)執(zhí)行 |
dispatch_once() | 一次性執(zhí)行 |
dispatch_apply() | 提交隊(duì)列 |
dispatch_queue_create() | 創(chuàng)建隊(duì)列 |
dispatch_group_create() | 創(chuàng)建隊(duì)列組 |
dispatch_group_async() | 提交任務(wù)到隊(duì)列組 |
dispatch_group_enter() / dispatch_group_leave() | 將隊(duì)列組中的任務(wù)未執(zhí)行完畢的任務(wù)數(shù)目加減1(兩個(gè)函數(shù)要配合使用) |
dispatch_group_notify() | 監(jiān)聽(tīng)隊(duì)列組執(zhí)行完畢 |
dispatch_group_wait() | 設(shè)置等待時(shí)間(返回 0成功,1失敗) |
注意:
1.所有的執(zhí)行都放到隊(duì)列中(queue),隊(duì)列的特點(diǎn)是FIFO(先提交的先執(zhí)行)
2.必須在主線程訪問(wèn) UIKit 的類(lèi)
3.并發(fā)隊(duì)列只在異步函數(shù)下才有效
基本使用
NSLog(@"當(dāng)前線程: %@", [NSThread currentThread]);
//獲取主隊(duì)列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//獲取全局并發(fā)隊(duì)列
dispatch_queue_t otherQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//同步函數(shù)(在當(dāng)前線程中執(zhí)行,不具備開(kāi)啟新線程的能力)
dispatch_sync(otherQueue, ^{
NSLog(@"同步 %@", [NSThread currentThread]);
});
//異步函數(shù)(在另一條線程中執(zhí)行,具備開(kāi)啟新線程的能力)
dispatch_async(otherQueue, ^{
NSLog(@"異步 %@", [NSThread currentThread]);
});
//輸出: 當(dāng)前線程: <NSThread: 0x7f81bac06670>{number = 1, name = main}
//輸出: 同步 <NSThread: 0x7f81bac06670>{number = 1, name = main}
//輸出: 異步 <NSThread: 0x7f81bae35be0>{number = 3, name = (null)}
延時(shí)執(zhí)行 dispatch_after()
dispatch_after()延遲一段時(shí)間把一項(xiàng)任務(wù)提交到隊(duì)列中執(zhí)行孵稽,返回之后就不能取消
常用來(lái)在在主隊(duì)列上延遲執(zhí)行一項(xiàng)任務(wù)
NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
//GCD延時(shí)調(diào)用(主線程)(主隊(duì)列)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"GCD延時(shí)(主線程) %@", [NSThread currentThread]);
});
//GCD延時(shí)調(diào)用(其他線程)(全局并發(fā)隊(duì)列)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"GCD延時(shí)(其他線程) %@", [NSThread currentThread]);
});
//輸出: 當(dāng)前線程 <NSThread: 0x7f8cb9701990>{number = 1, name = main}
//輸出: GCD延時(shí)(主線程) <NSThread: 0x7f8cb9701990>{number = 1, name = main}
//輸出: GCD延時(shí)(其他線程) <NSThread: 0x7f8cb9513ee0>{number = 3, name = (null)}
一次性執(zhí)行 dispatch_once()
整個(gè)程序運(yùn)行中,只會(huì)執(zhí)行一次 (默認(rèn)線程是安全的)
dispatch_once() 以線程安全的方式執(zhí)行且僅執(zhí)行其代碼塊一次
for (NSInteger i = 0; i < 10; i++) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"GCD一次性執(zhí)行(默認(rèn)線程是安全的)");
});
}
//輸出: GCD一次性執(zhí)行(默認(rèn)線程是安全的)
//使用GCD初始化單例
+ (instancetype)sharedManager {
static PhotoManager *sharedPhotoManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPhotoManager = [[PhotoManager alloc] init];
});
return sharedPhotoManager;
}
提交 dispatch_apply()
把一項(xiàng)任務(wù)提交到隊(duì)列中多次執(zhí)行许起,具體是并行執(zhí)行還是串行執(zhí)行由隊(duì)列本身決定
dispatch_apply不會(huì)立刻返回十偶,在執(zhí)行完畢后才會(huì)返回,是同步的調(diào)用园细。
隊(duì)列
任務(wù)1,任務(wù)2依次執(zhí)行,所有任務(wù)都執(zhí)行成功后回到主線程
(效率不高)
NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//全局并發(fā)隊(duì)列
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
}
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
}
dispatch_async(dispatch_get_main_queue(), ^{
//主隊(duì)列
NSLog(@"主線程執(zhí)行(刷新UI) %@", [NSThread currentThread]);
});
});
//輸出: 當(dāng)前線程 <NSThread: 0x7fa78040b8b0>{number = 1, name = main}
//輸出: 任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
//輸出: 主線程(刷新UI) <NSThread: 0x7f9da1705940>{number = 1, name = main}
隊(duì)列組
任務(wù)1,任務(wù)2同時(shí)執(zhí)行,所有任務(wù)都執(zhí)行成功后回到主線程
(效率高)
NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
//(1)創(chuàng)建一個(gè)隊(duì)列組
dispatch_group_t group= dispatch_group_create();
//(2)開(kāi)啟任務(wù)1
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
}
});
//(3)開(kāi)啟任務(wù)2
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
}
});
//(4)所有任務(wù)執(zhí)行完畢,回到主線程
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"主線程(刷新UI) %@", [NSThread currentThread]);
});
//輸出: 當(dāng)前線程 <NSThread: 0x7fd951704e70>{number = 1, name = main}
//輸出: 任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
//輸出: 任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
//輸出: 任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
//輸出: 任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
//輸出: 任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
//輸出: 主線程(刷新UI) <NSThread: 0x7ff65a406fb0>{number = 1, name = main}
串行與并發(fā)
串行隊(duì)列
一個(gè)任務(wù)執(zhí)行完畢后惦积,再執(zhí)行下一個(gè)任務(wù)
主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列,放在主隊(duì)列中的任務(wù),都會(huì)放到主線程中執(zhí)行
//(1)使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列
//參數(shù)1: 隊(duì)列名稱(chēng)
//參數(shù)2: 隊(duì)列屬性 (一般用NULL)
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
//(2)使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列)
dispatch_queue_t serialMainQueue = dispatch_get_main_queue();
并發(fā)隊(duì)列
多個(gè)任務(wù)并發(fā)執(zhí)行(自動(dòng)開(kāi)啟多個(gè)線程同時(shí)執(zhí)行任務(wù))
<u>并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效!!!</u>
GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列,供整個(gè)應(yīng)用使用猛频,不需要手動(dòng)創(chuàng)建
并發(fā)隊(duì)列優(yōu)先級(jí) | 快捷值 | 優(yōu)先級(jí) |
---|---|---|
DISPATCH_QUEUE_PRIORITY_HIGH | 2 | 高 |
DISPATCH_QUEUE_PRIORITY_DEFAULT | 0 | 中(默認(rèn)) |
DISPATCH_QUEUE_PRIORITY_LOW | (-2) | 低 |
DISPATCH_QUEUE_PRIORITY_BACKGROUND | INT16_MIN | 后臺(tái) |
//(1)使用dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊(duì)列
//參數(shù)1: 優(yōu)先級(jí)
//參數(shù)2: 暫時(shí)無(wú)用參數(shù) (傳0)
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
異步函數(shù)_并發(fā)隊(duì)列
(開(kāi)啟新線程,并發(fā)執(zhí)行任務(wù))
NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)3 %@", [NSThread currentThread]);
});
//輸出: 當(dāng)前線程 <NSThread: 0x7fbe83c067c0>{number = 1, name = main}
//輸出: 任務(wù)1 <NSThread: 0x7fb84160ed90>{number = 3, name = (null)}
//輸出: 任務(wù)3 <NSThread: 0x7fb841752940>{number = 4, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7fb8414167b0>{number = 5, name = (null)}
異步函數(shù)_串行隊(duì)列
(開(kāi)啟新線程,串行執(zhí)行任務(wù))
NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
//創(chuàng)建串行隊(duì)列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
dispatch_async(serialQueue, ^{
NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"任務(wù)3 %@", [NSThread currentThread]);
});
//輸出: 當(dāng)前線程 <NSThread: 0x7fc192e05380>{number = 1, name = main}
//輸出: 任務(wù)1 <NSThread: 0x7fc192c16670>{number = 3, name = (null)}
//輸出: 任務(wù)2 <NSThread: 0x7fc192c16670>{number = 3, name = (null)}
//輸出: 任務(wù)3 <NSThread: 0x7fc192c16670>{number = 3, name = (null)}
同步函數(shù)_并發(fā)隊(duì)列
(不會(huì)開(kāi)啟新線程,并發(fā)執(zhí)行任務(wù)失效!)
NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
});
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
});
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任務(wù)3 %@", [NSThread currentThread]);
});
//輸出: 當(dāng)前線程 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main}
//輸出: 任務(wù)1 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main}
//輸出: 任務(wù)2 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main}
//輸出: 任務(wù)3 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main}
同步函數(shù)_串行隊(duì)列
(不會(huì)開(kāi)啟新線程,串行執(zhí)行任務(wù))
NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
//創(chuàng)建串行隊(duì)列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
dispatch_sync(serialQueue, ^{
NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"任務(wù)3 %@", [NSThread currentThread]);
});
//輸出: 當(dāng)前線程 <NSThread: 0x7f8c0b407f00>{number = 1, name = main}
//輸出: 任務(wù)1 <NSThread: 0x7f8c0b407f00>{number = 1, name = main}
//輸出: 任務(wù)2 <NSThread: 0x7f8c0b407f00>{number = 1, name = main}
//輸出: 任務(wù)3 <NSThread: 0x7f8c0b407f00>{number = 1, name = main}