GCD指南
基本概念
串行
:多個任務(wù)在一條線程
上順序
執(zhí)行。并發(fā)
:多個任務(wù)在多條線程
上同時
執(zhí)行。同步
:立即在當(dāng)前線程
上執(zhí)行任務(wù),待到
任務(wù)結(jié)束后让蕾,再執(zhí)行后面的任務(wù)。異步
:立即在另一條線程
上執(zhí)行任務(wù)或听,不等待任務(wù)結(jié)束探孝,立即返回
,以執(zhí)行后面的任務(wù)誉裆。注意再姑,同步和異步都會將任務(wù)添加至
目標(biāo)線程的末尾
,而非在當(dāng)前位置插入
找御。
隊(duì)列和執(zhí)行函數(shù)
- 隊(duì)列:
- 任務(wù)之間的
派發(fā)順序
:FIFO元镀。 - 任務(wù)之間的
執(zhí)行順序
:串行(前一個執(zhí)行任務(wù)完畢绍填,再執(zhí)行下一個);并行(不等前一個任務(wù)執(zhí)行完畢栖疑,下一個就執(zhí)行) 串行隊(duì)列
-
局部
串行隊(duì)列
// 創(chuàng)建一個局部串行隊(duì)列
dispatch_queue_t serialQueue = dispatch_queue_create("SerialQ", DISPATCH_QUEUE_SERIAL);
-
主隊(duì)列
:在主線程上執(zhí)行隊(duì)列任務(wù)的串行隊(duì)列讨永。通常用于將子線程數(shù)據(jù)同步至主線程
。
// 獲取主隊(duì)列(全局串行隊(duì)列)
dispatch_queue_t mainQueue = dispatch_get_main_queue();
并行隊(duì)列
- 局部并發(fā)隊(duì)列
// 創(chuàng)建一個局部并發(fā)隊(duì)列
dispatch_queue_t concurrentQueue = dispatch_queue_create("ConcurrentQ", DISPATCH_QUEUE_CONCURRENT);
- 全局并發(fā)隊(duì)列
// 獲取全局并發(fā)隊(duì)列
dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(0, 0); // 參數(shù)傳入兩個0即可
- 執(zhí)行函數(shù)
- 執(zhí)行任務(wù)的
線程
:同步(當(dāng)前線程)遇革;異步(其他線程)卿闹。 - 線程
是否等待任務(wù)結(jié)束
:(同步)等待;異步(不等待)萝快。 -
同步執(zhí)行
锻霎,將一個或多個任務(wù)添加至目標(biāo)線程末尾,會阻塞當(dāng)前線程揪漩。
// 同步執(zhí)行一個隊(duì)列(串行/并行)中的任務(wù)
dispatch_sync(aQueue, ^{
// 任務(wù)
});
-
異步執(zhí)行
旋恼,將一個或多個任務(wù)添加至目標(biāo)線程末尾,不會阻塞當(dāng)前線程奄容。
// 異步執(zhí)行一個隊(duì)列(串行/并行)中的任務(wù)
dispatch_async(aQueue, ^{
// 任務(wù)
});
隊(duì)列和執(zhí)行函數(shù)組合
組合 | 同步執(zhí)行 | 異步執(zhí)行 |
---|---|---|
局部串行隊(duì)列 | 當(dāng)前線程冰更,順序執(zhí)行 | 其他線程(一條),順序執(zhí)行 |
主隊(duì)列 | DeadLock | 主線程昂勒,順序執(zhí)行 |
并行隊(duì)列 | 當(dāng)前線程蜀细,順序執(zhí)行 | 其他線程(多條),并行執(zhí)行 |
-
死鎖/DeadLock
:假設(shè)有串行隊(duì)列q
戈盈,其中有任務(wù)t1
奠衔,t1又包含向隊(duì)列q提交同步執(zhí)行任務(wù)t2
的代碼。這時塘娶,q等待t1執(zhí)行完畢涣觉,t1等待t2執(zhí)行完畢,但由于t2需要等待隊(duì)列q中的所有操作執(zhí)行完畢才能執(zhí)行血柳,就造成了DeadLock狀態(tài)官册。
串行隊(duì)列q--(等待)-->任務(wù)t1--(等待)-->任務(wù)t2--(等待)-->隊(duì)列q--->無限循環(huán)
盡管死鎖多發(fā)生在
串行隊(duì)列
,但對于并行隊(duì)列
难捌, 也要避免在任務(wù)中向任務(wù)所在的隊(duì)列提交同步執(zhí)行任務(wù)
驰后。異步執(zhí)行
永遠(yuǎn)不會造成DeadLock驻债。上述表格中捂蕴,只使用
異步執(zhí)行 + 各種隊(duì)列
的組合端盆。
進(jìn)程間通信
/**
在子線程上處理耗時操作,將結(jié)果利用主隊(duì)列同步至主線程击敌。
*/
dispatch_async(dispatch_get_global_queue(0, 0), ^{
id result = [self doMyWork]; // 在子線程上應(yīng)該執(zhí)行的任務(wù)
/**
回到主線程處理結(jié)果
*/
dispatch_async(dispatch_get_main_queue(), ^{
[self processResult:result];
});
});
任務(wù)分組
- 如果需要等待
多個并發(fā)任務(wù)
完成后再執(zhí)行某些操作介返,使用任務(wù)分組。
// 創(chuàng)建一個分組對象
dispatch_group_t group = dispatch_group_create();
// 向隊(duì)列提交異步執(zhí)行任務(wù),并將這個任務(wù)納入分組
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"1");
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"3");
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"2");
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"3");
[NSThread sleepForTimeInterval:3];
});
/**
沒有通過分組提交至隊(duì)列的任務(wù)不會被納入分組
*/
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"獨(dú)立于分組之外的任務(wù)");
});
// 監(jiān)聽分組內(nèi)所有任務(wù)是否執(zhí)行完畢
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"所有操作已經(jīng)執(zhí)行完畢");
});
阻塞隊(duì)列
- 注意圣蝎,對于全局隊(duì)列來說刃宵,
阻塞無效
。
dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"1");
});
dispatch_async(queue, ^{
NSLog(@"2");
[NSThread sleepForTimeInterval:3];
});
/**
向隊(duì)列提交一個阻塞任務(wù)徘公,當(dāng)隊(duì)列執(zhí)行至阻塞任務(wù)時牲证,不會立即派發(fā)。
相反关面,隊(duì)列會等到當(dāng)前所有正在執(zhí)行的任務(wù)返回后坦袍,再派發(fā)阻塞任務(wù)。
阻塞任務(wù)之后的任務(wù)也必須等待其執(zhí)行完畢才能執(zhí)行等太,即前后阻塞捂齐。
*/
dispatch_barrier_async(queue, ^{
NSLog(@"3(阻塞任務(wù))");
[NSThread sleepForTimeInterval:3];
});
dispatch_async(queue, ^{
NSLog(@"4");
});