1.GCD的概念
GCD為Grand Central Dispatch的縮寫(xiě)脆丁。
它主要用于優(yōu)化應(yīng)用程序以支持多核處理器以及其他對(duì)稱(chēng)多處理系統(tǒng)句喷。它是一個(gè)在線(xiàn)程池模式的基礎(chǔ)上執(zhí)行的并行任務(wù)丐膝。在Mac OS X 10.6雪豹中首次推出鞍历,也可在IOS 4及以上版本使用。
2.GCD的隊(duì)列和任務(wù)
GCD包括兩個(gè)核心概念:隊(duì)列和任務(wù)
2.1隊(duì)列
隊(duì)列是一種特殊的線(xiàn)性表跨算,遵循FIFO(先進(jìn)先出)原則轻要,新添加的任務(wù)在隊(duì)尾,執(zhí)行任務(wù)的時(shí)候從隊(duì)首開(kāi)始讀取并執(zhí)行旱爆。隊(duì)列分為串行隊(duì)列和并行隊(duì)列舀射,區(qū)別主要是:隊(duì)列中任務(wù)執(zhí)行的順序不同,開(kāi)啟的線(xiàn)程數(shù)也不同怀伦。
串行隊(duì)列
每個(gè)時(shí)間段只有一個(gè)任務(wù)在執(zhí)行脆烟,只開(kāi)啟一個(gè)線(xiàn)程,一個(gè)任務(wù)執(zhí)行完以后再執(zhí)行下一個(gè)任務(wù)房待。
并行隊(duì)列
可以有多個(gè)任務(wù)在并發(fā)執(zhí)行邢羔,可以開(kāi)啟多個(gè)線(xiàn)程同時(shí)處理多個(gè)任務(wù)。
2.2任務(wù)
任務(wù)就是需要執(zhí)行的一組操作桑孩,在GCD是放在block中的那一段代碼拜鹤,任務(wù)分為同步任務(wù)和異步任務(wù),區(qū)別是:是否等待隊(duì)列的任務(wù)執(zhí)行結(jié)束流椒,以及是否具備開(kāi)啟新線(xiàn)程的能力敏簿。
同步sync
同步任務(wù)會(huì)等待操作執(zhí)行完畢,再執(zhí)行block外的操作镣隶,只能在當(dāng)前線(xiàn)程中執(zhí)行任務(wù)极谊。
異步async
異步任務(wù)不會(huì)等待操作執(zhí)行完畢,會(huì)直接繼續(xù)執(zhí)行block外的操作安岂,可以在開(kāi)啟新的線(xiàn)程執(zhí)行任務(wù)。
3.GCD的具體使用
3.1創(chuàng)建隊(duì)列
dispatch_queue_t serial_queue = dispatch_queue_create("serial_queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t concurrent_queue = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
3.2隊(duì)列和任務(wù)的簡(jiǎn)單組合
3.2.1串行+同步
// 串行隊(duì)列+同步
NSLog(@"主流程start--%@", [NSThread currentThread]);
dispatch_sync(serial_queue, ^{
NSLog(@"同步1--操作1--%@", [NSThread currentThread]);
sleep(3);
NSLog(@"同步1--操作2--%@", [NSThread currentThread]);
});
dispatch_sync(serial_queue, ^{
NSLog(@"同步2--操作1--%@", [NSThread currentThread]);
sleep(1);
NSLog(@"同步2--操作2--%@", [NSThread currentThread]);
});
dispatch_sync(serial_queue, ^{
NSLog(@"同步3--操作1--%@", [NSThread currentThread]);
sleep(2);
NSLog(@"同步3--操作2--%@", [NSThread currentThread]);
});
NSLog(@"主流程end-----%@", [NSThread currentThread]);
2021-03-20 17:08:38.693421+0800 test1[8934:9017257] 主流程start--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:38.693566+0800 test1[8934:9017257] 同步1--操作1--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:41.694375+0800 test1[8934:9017257] 同步1--操作2--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:41.694603+0800 test1[8934:9017257] 同步2--操作1--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:42.695118+0800 test1[8934:9017257] 同步2--操作2--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:42.695589+0800 test1[8934:9017257] 同步3--操作1--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:44.696285+0800 test1[8934:9017257] 同步3--操作2--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:44.696645+0800 test1[8934:9017257] 主流程end-----<NSThread: 0x60000102dd80>{number = 1, name = main}
3.2.2并行+同步
// 并行隊(duì)列+同步
NSLog(@"主流程start--%@", [NSThread currentThread]);
dispatch_sync(concurrent_queue, ^{
NSLog(@"同步1--操作1--%@", [NSThread currentThread]);
sleep(3);
NSLog(@"同步1--操作2--%@", [NSThread currentThread]);
});
dispatch_sync(concurrent_queue, ^{
NSLog(@"同步2--操作1--%@", [NSThread currentThread]);
sleep(1);
NSLog(@"同步2--操作2--%@", [NSThread currentThread]);
});
dispatch_sync(concurrent_queue, ^{
NSLog(@"同步3--操作1--%@", [NSThread currentThread]);
sleep(2);
NSLog(@"同步3--操作2--%@", [NSThread currentThread]);
});
NSLog(@"主流程end-----%@", [NSThread currentThread]);
2021-03-20 17:07:19.312244+0800 test1[8866:9015712] 主流程start--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:19.312456+0800 test1[8866:9015712] 同步1--操作1--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:22.313735+0800 test1[8866:9015712] 同步1--操作2--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:22.314070+0800 test1[8866:9015712] 同步2--操作1--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:23.315434+0800 test1[8866:9015712] 同步2--操作2--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:23.315738+0800 test1[8866:9015712] 同步3--操作1--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:25.317084+0800 test1[8866:9015712] 同步3--操作2--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:25.317458+0800 test1[8866:9015712] 主流程end-----<NSThread: 0x600002961dc0>{number = 1, name = main}
3.2.3串行+異步
// 串行隊(duì)列+異步
NSLog(@"主流恒start--%@", [NSThread currentThread]);
dispatch_async(serial_queue, ^{
NSLog(@"異步1--操作1--%@", [NSThread currentThread]);
sleep(3);
NSLog(@"異步1--操作2--%@", [NSThread currentThread]);
});
dispatch_async(serial_queue, ^{
NSLog(@"異步2--操作1--%@", [NSThread currentThread]);
sleep(1);
NSLog(@"異步2--操作2--%@", [NSThread currentThread]);
});
dispatch_async(serial_queue, ^{
NSLog(@"異步3--操作1--%@", [NSThread currentThread]);
sleep(2);
NSLog(@"異步3--操作2--%@", [NSThread currentThread]);
});
NSLog(@"主流程end-----%@", [NSThread currentThread]);
2021-03-20 16:52:39.159286+0800 test1[8200:9002593] 主流恒start--<NSThread: 0x600002b2ab80>{number = 1, name = main}
2021-03-20 16:52:39.159443+0800 test1[8200:9002593] 主流程end-----<NSThread: 0x600002b2ab80>{number = 1, name = main}
2021-03-20 16:52:39.159462+0800 test1[8200:9002672] 異步1--操作1--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:42.164330+0800 test1[8200:9002672] 異步1--操作2--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:42.164759+0800 test1[8200:9002672] 異步2--操作1--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:43.166518+0800 test1[8200:9002672] 異步2--操作2--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:43.166932+0800 test1[8200:9002672] 異步3--操作1--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:45.173185+0800 test1[8200:9002672] 異步3--操作2--<NSThread: 0x600002b42040>{number = 6, name = (null)}
3.2.4并行+異步
NSLog(@"主流恒start--%@", [NSThread currentThread]);
dispatch_async(concurrent_queue, ^{
NSLog(@"異步1--操作1--%@", [NSThread currentThread]);
sleep(3);
NSLog(@"異步1--操作2--%@", [NSThread currentThread]);
});
dispatch_async(concurrent_queue, ^{
NSLog(@"異步2--操作1--%@", [NSThread currentThread]);
sleep(1);
NSLog(@"異步2--操作2--%@", [NSThread currentThread]);
});
dispatch_async(concurrent_queue, ^{
NSLog(@"異步3--操作1--%@", [NSThread currentThread]);
sleep(2);
NSLog(@"異步3--操作2--%@", [NSThread currentThread]);
});
NSLog(@"主流程end-----%@", [NSThread currentThread]);
2021-03-20 16:44:46.396510+0800 test1[7871:8996717] 主流恒start--<NSThread: 0x600000b8dd80>{number = 1, name = main}
2021-03-20 16:44:46.396648+0800 test1[7871:8996717] 主流程end-----<NSThread: 0x600000b8dd80>{number = 1, name = main}
2021-03-20 16:44:46.396687+0800 test1[7871:8996802] 異步1--操作1--<NSThread: 0x600000be8080>{number = 3, name = (null)}
2021-03-20 16:44:46.396702+0800 test1[7871:8996806] 異步2--操作1--<NSThread: 0x600000b9c900>{number = 5, name = (null)}
2021-03-20 16:44:46.396707+0800 test1[7871:8996803] 異步3--操作1--<NSThread: 0x600000bb9f40>{number = 4, name = (null)}
2021-03-20 16:44:47.398008+0800 test1[7871:8996806] 異步2--操作2--<NSThread: 0x600000b9c900>{number = 5, name = (null)}
2021-03-20 16:44:48.397575+0800 test1[7871:8996803] 異步3--操作2--<NSThread: 0x600000bb9f40>{number = 4, name = (null)}
2021-03-20 16:44:49.398078+0800 test1[7871:8996802] 異步1--操作2--<NSThread: 0x600000be8080>{number = 3, name = (null)}
結(jié)論
1.對(duì)于同步執(zhí)行的任務(wù)帆吻,不管是放在并行隊(duì)列還是串行隊(duì)列中域那,都是按順序執(zhí)行,且當(dāng)上一個(gè)任務(wù)完成以后才執(zhí)行下一個(gè)任務(wù)猜煮。
2.異步執(zhí)行的任務(wù)次员,串行隊(duì)列會(huì)開(kāi)啟一個(gè)新線(xiàn)程,串行執(zhí)行任務(wù)王带,并行隊(duì)列會(huì)開(kāi)啟多個(gè)新線(xiàn)程淑蔚,并行執(zhí)行任務(wù)。
image.png
3.3死鎖
// 串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
// 異步函數(shù)
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
結(jié)果:輸出1愕撰、5刹衫、2以后產(chǎn)生死鎖崩潰
造成死鎖的原因:輸出2以后醋寝,將輸出3的這個(gè)同步函數(shù)(紅框部分)添加到同步隊(duì)列,那么如果要執(zhí)行紅框部分的代碼带迟,按照隊(duì)列先進(jìn)先出的規(guī)則音羞,則需要先執(zhí)行完排在前面的異步函數(shù)(綠框部分),但是該異步函數(shù)又需等待紅框部分執(zhí)行完以后仓犬,產(chǎn)生死鎖嗅绰。
結(jié)論:在串行隊(duì)列中添加同步任務(wù)時(shí),注意線(xiàn)程阻塞的問(wèn)題搀继,iOS主隊(duì)列是串行隊(duì)列窘面,如果在主線(xiàn)程執(zhí)行過(guò)程中向主隊(duì)列中添加同步操作時(shí)也會(huì)產(chǎn)生死鎖,另外開(kāi)辟一個(gè)線(xiàn)程向主隊(duì)列添加同步操作則不會(huì)產(chǎn)生死鎖叽躯。
例如在viewDidLoad函數(shù)中調(diào)用serialQueueProblem會(huì)在輸出1以后產(chǎn)生死鎖崩潰财边。
- (void)serialQueueProblem{
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
如果調(diào)用方式換成這樣則正常輸出123
[NSThread detachNewThreadSelector:@selector(serialQueueProblem) toTarget:self withObject:nil];
3.4其他用法
3.4.1 dispatch_once
- (void)dispatchOnce{
static dispatch_once_t onceToken;
NSLog(@"%ld", onceToken);
dispatch_once(&onceToken, ^{
// 只會(huì)執(zhí)行一次
NSLog(@"1%@", [NSThread currentThread]);
});
}
調(diào)用三次的執(zhí)行結(jié)果
2021-03-21 18:17:02.376201+0800 test1[67067:9754075] 0
2021-03-21 18:17:02.376363+0800 test1[67067:9754075] 1<NSThread: 0x600002d85e40>{number = 1, name = main}
2021-03-21 18:17:02.376480+0800 test1[67067:9754075] -1
2021-03-21 18:17:02.376559+0800 test1[67067:9754075] -1
常用于實(shí)現(xiàn)一個(gè)單例
+ (instancetype)sharedInstance {
static XXObject *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[XXObject alloc] init];
});
return _instance;
}
3.4.2 dispatch_after
多長(zhǎng)時(shí)間之后將任務(wù)添加到隊(duì)列中,所以任務(wù)并不是精準(zhǔn)的三秒之后再執(zhí)行
第一個(gè)參數(shù):dispatch_time_t類(lèi)型险毁,用于指定延遲時(shí)間
第二個(gè)參數(shù):指定要追加處理的隊(duì)列
第三個(gè)參數(shù):指定要執(zhí)行的任務(wù)Block
- (void)dispatchAfter{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"1%@", [NSThread currentThread]);
});
NSLog(@"2%@", [NSThread currentThread]);
}
2021-03-21 18:21:35.749123+0800 test1[67266:9757808] 2<NSThread: 0x60000057d0c0>{number = 1, name = main}
2021-03-21 18:21:39.037124+0800 test1[67266:9757808] 1<NSThread: 0x60000057d0c0>{number = 1, name = main}
3.4.3 Dispatch Source
Dispatch Source的種類(lèi):
1制圈、DISPATCH_SOURCE_TYPE_DATA_ADD 變量增加
2、DISPATCH_SOURCE_TYPE_DATA_OR 變量 OR
3畔况、DISPATCH_SOURCE_TYPE_MACH_SEND MACH端口發(fā)送
4鲸鹦、DISPATCH_SOURCE_TYPE_MACH_RECV MACH端口接收
5、DISPATCH_SOURCE_TYPE_MEMORYPRESSURE 內(nèi)存壓力 (注:iOS8后可用)
6跷跪、DISPATCH_SOURCE_TYPE_PROC 檢測(cè)到與進(jìn)程相關(guān)的事件
7馋嗜、DISPATCH_SOURCE_TYPE_READ 可讀取文件映像
8、DISPATCH_SOURCE_TYPE_SIGNAL 接收信號(hào)
9吵瞻、DISPATCH_SOURCE_TYPE_TIMER 定時(shí)器
10葛菇、DISPATCH_SOURCE_TYPE_VNODE 文件系統(tǒng)有變更
11、DISPATCH_SOURCE_TYPE_WRITE 可寫(xiě)入文件映像
使用DISPATCH_SOURCE_TYPE_TIMER可以實(shí)現(xiàn)一個(gè)每三秒執(zhí)行一次的定時(shí)器
- (void)dispatchSource{
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(_timer, ^{
NSLog(@"1%@", [NSThread currentThread]);
});
NSLog(@"2%@", [NSThread currentThread]);
dispatch_resume(_timer);
NSLog(@"3%@", [NSThread currentThread]);
}
2021-03-21 18:39:52.466493+0800 test1[68104:9773071] 2<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:39:52.466664+0800 test1[68104:9773071] 3<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:39:52.476591+0800 test1[68104:9773071] 1<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:39:55.467553+0800 test1[68104:9773071] 1<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:39:58.467371+0800 test1[68104:9773071] 1<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:40:01.467143+0800 test1[68104:9773071] 1<NSThread: 0x600000c492c0>{number = 1, name = main}
3.4.4 dispatch_apply
按指定的次數(shù)將指定的Block追加到指定的Dispatch Queue中橡羞,并等待全部處理執(zhí)行結(jié)束眯停,用在并行隊(duì)列執(zhí)行順序無(wú)序,用在串行隊(duì)列則按順序執(zhí)行
- (void)dispatchApply{
dispatch_queue_t queue1 = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("aaa", DISPATCH_QUEUE_SERIAL);
dispatch_apply(5, queue1, ^(size_t index) {
NSLog(@"并行隊(duì)列%ld%@", index, [NSThread mainThread]);
});
NSLog(@"并行結(jié)束-----");
dispatch_apply(5, queue2, ^(size_t index) {
NSLog(@"串行隊(duì)列%ld%@", index, [NSThread mainThread]);
});
NSLog(@"串行結(jié)束-----");
}
2021-03-21 18:55:42.463961+0800 test1[68871:9787727] 并行隊(duì)列3<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.463966+0800 test1[68871:9787725] 并行隊(duì)列1<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.463966+0800 test1[68871:9787728] 并行隊(duì)列2<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.464026+0800 test1[68871:9787730] 并行隊(duì)列4<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.463961+0800 test1[68871:9787529] 并行隊(duì)列0<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464151+0800 test1[68871:9787529] 并行結(jié)束-----
2021-03-21 18:55:42.464242+0800 test1[68871:9787529] 串行隊(duì)列0<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464341+0800 test1[68871:9787529] 串行隊(duì)列1<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464434+0800 test1[68871:9787529] 串行隊(duì)列2<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464674+0800 test1[68871:9787529] 串行隊(duì)列3<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464891+0800 test1[68871:9787529] 串行隊(duì)列4<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.465079+0800 test1[68871:9787529] 串行結(jié)束-----
3.4.5 dispatch_barrier
- 柵欄函數(shù)之前的任務(wù)執(zhí)行完以后卿泽,并且柵欄函數(shù)執(zhí)行完莺债,才執(zhí)行后面的操作
- 串行隊(duì)列或者系統(tǒng)提供的全局并發(fā)隊(duì)列,這個(gè)柵欄函數(shù)的作用等同于一個(gè)同步函數(shù)的作用
- dispatch_barrier_sync和dispatch_barrier_async的區(qū)別是,在當(dāng)前線(xiàn)程中的操作签夭,是否需要等待自己執(zhí)行完再執(zhí)行
- (void)dispatchBarrier{
dispatch_queue_t queue = dispatch_queue_create("bbb", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
sleep(2);
NSLog(@"1%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"2%@", [NSThread currentThread]);
});
dispatch_barrier_sync(queue, ^{
sleep(1);
NSLog(@"barrier%@", [NSThread currentThread]);
});
NSLog(@"barrier done");
dispatch_async(queue, ^{
sleep(2);
NSLog(@"3%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"4%@", [NSThread currentThread]);
});
}
2021-03-21 19:11:09.974409+0800 test1[69598:9801166] 2<NSThread: 0x600000850640>{number = 6, name = (null)}
2021-03-21 19:11:10.974576+0800 test1[69598:9801168] 1<NSThread: 0x600000850600>{number = 4, name = (null)}
2021-03-21 19:11:11.975488+0800 test1[69598:9801093] barrier<NSThread: 0x6000008220c0>{number = 1, name = main}
2021-03-21 19:11:11.975850+0800 test1[69598:9801093] barrier done
2021-03-21 19:11:12.980667+0800 test1[69598:9801166] 4<NSThread: 0x600000850640>{number = 6, name = (null)}
2021-03-21 19:11:13.977532+0800 test1[69598:9801168] 3<NSThread: 0x600000850600>{number = 4, name = (null)}
如果把dispatch_barrier_sync換成dispatch_barrier_async
2021-03-21 19:12:25.502966+0800 test1[69660:9802632] barrier done
2021-03-21 19:12:26.503388+0800 test1[69660:9802717] 2<NSThread: 0x600001504280>{number = 6, name = (null)}
2021-03-21 19:12:27.507601+0800 test1[69660:9802728] 1<NSThread: 0x6000015823c0>{number = 3, name = (null)}
2021-03-21 19:12:28.511868+0800 test1[69660:9802728] barrier<NSThread: 0x6000015823c0>{number = 3, name = (null)}
2021-03-21 19:12:29.514776+0800 test1[69660:9802718] 4<NSThread: 0x600001581bc0>{number = 4, name = (null)}
2021-03-21 19:12:30.515791+0800 test1[69660:9802728] 3<NSThread: 0x6000015823c0>{number = 3, name = (null)}
3.5 diapatch_group
將要并發(fā)執(zhí)行的多個(gè)任務(wù)合并為一組齐邦,這樣調(diào)用者就可以知道這些任務(wù)何時(shí)能全部執(zhí)行完
3.5.1 新建group
dispatch_group_t group = dispatch_group_create();
3.5.2 將任務(wù)添加到group
用法一:dispatch_group_async
- (void)dispatchGroup1{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
sleep(2);
NSLog(@"1%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
sleep(1);
NSLog(@"2%@", [NSThread currentThread]);
});
dispatch_group_notify(group, queue, ^{
NSLog(@"notify%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
sleep(1);
NSLog(@"3%@", [NSThread currentThread]);
});
}
2021-03-21 20:28:06.280832+0800 test1[72687:9846592] 2<NSThread: 0x600001854a00>{number = 4, name = (null)}
2021-03-21 20:28:06.280833+0800 test1[72687:9846593] 3<NSThread: 0x60000183a7c0>{number = 3, name = (null)}
2021-03-21 20:28:07.279869+0800 test1[72687:9846591] 1<NSThread: 0x60000184e300>{number = 7, name = (null)}
2021-03-21 20:28:07.280195+0800 test1[72687:9846591] notify<NSThread: 0x60000184e300>{number = 7, name = (null)}
用法二:dispatch_group_enter+dispatch_group_leave配對(duì)使用
- (void)dispatchGroup2{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("111", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_enter(group);
dispatch_async(queue, ^{
sleep(2);
NSLog(@"1%@", [NSThread currentThread]);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"2%@", [NSThread currentThread]);
dispatch_group_leave(group);
});
dispatch_group_notify(group, queue, ^{
NSLog(@"notify%@", [NSThread currentThread]);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"3%@", [NSThread currentThread]);
dispatch_group_leave(group);
});
}
2021-03-21 20:44:53.567884+0800 test1[73477:9862570] 2<NSThread: 0x6000024a04c0>{number = 5, name = (null)}
2021-03-21 20:44:53.567930+0800 test1[73477:9862573] 3<NSThread: 0x6000024946c0>{number = 3, name = (null)}
2021-03-21 20:44:54.567761+0800 test1[73477:9862572] 1<NSThread: 0x6000024bf380>{number = 6, name = (null)}
2021-03-21 20:44:54.568120+0800 test1[73477:9862572] notify<NSThread: 0x6000024bf380>{number = 6, name = (null)}
3.5.3 監(jiān)聽(tīng)group里面的任務(wù)是否都完成
方法一:dispatch_group_notify使用方法如3.5.2
方法二:dispatch_group_wait設(shè)置等待時(shí)間,在等待時(shí)間結(jié)束后第租,如果還沒(méi)有執(zhí)行完任務(wù)組措拇,則返回。返回0代表執(zhí)行成功慎宾,非0則執(zhí)行失敗
- (void)dispatchGroupWait{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
sleep(2);
NSLog(@"1%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
sleep(1);
NSLog(@"2%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
sleep(1);
NSLog(@"3%@", [NSThread currentThread]);
});
long ret = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)));
NSLog(@"ret = %ld", ret);
}
2021-03-21 20:57:35.552239+0800 test1[74073:9874594] 2<NSThread: 0x60000376c500>{number = 5, name = (null)}
2021-03-21 20:57:35.552252+0800 test1[74073:9874597] 3<NSThread: 0x60000376e540>{number = 3, name = (null)}
2021-03-21 20:57:36.552133+0800 test1[74073:9874595] 1<NSThread: 0x600003738780>{number = 4, name = (null)}
2021-03-21 20:57:36.552526+0800 test1[74073:9874485] ret = 0
如果把dispatch_group_wait的等待時(shí)長(zhǎng)減少到1秒則返回非0
3.6 信號(hào)量 dispatch_semaphore
- dispatch_semaphore_create(long value);創(chuàng)建信號(hào)量丐吓,參數(shù)為設(shè)置信號(hào)量的初始值
- dispatch_semaphore_signal(dispatch_semaphore_t dsema);發(fā)送信號(hào)量浅悉,信號(hào)量的值+1
- dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);等待信號(hào)量,第一個(gè)為當(dāng)前等待的信號(hào)量汰蜘,第二個(gè)參數(shù)為超時(shí)時(shí)間仇冯。在信號(hào)量≤0的時(shí)候會(huì)一直等待,直到超時(shí)族操,并且會(huì)阻塞該線(xiàn)程苛坚,當(dāng)信號(hào)量>0時(shí)會(huì)繼續(xù)執(zhí)行,信號(hào)量-1色难。
使用信號(hào)量控制最大并發(fā)數(shù)
- (void)dispatchSemaphore{
dispatch_group_t group = dispatch_group_create();
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
dispatch_queue_t queue = dispatch_queue_create("qqq", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i ++) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{
sleep(1);
NSLog(@"%d%@", i, [NSThread currentThread]);
dispatch_semaphore_signal(semaphore);
});
}
dispatch_group_notify(group, queue, ^{
NSLog(@"done");
});
}