GCD 隊列組:dispatch_group
? ? ? ? 有時候我們會有這樣的需求:分別異步執(zhí)行多個耗時任務(wù)洞就,當多個耗時任務(wù)都執(zhí)行完畢后盆繁,再回到指定線程執(zhí)行任務(wù)。這時候我們可以用到 GCD 的隊列組旬蟋。調(diào)用隊列組的dispatch_group_async先把任務(wù)放到隊列中油昂,然后將隊列放入隊列組中∏惴。或者使用隊列組的dispatch_group_enter冕碟、dispatch_group_leave組合來實現(xiàn)。調(diào)用隊列組的dispatch_group_notify回到指定線程執(zhí)行任務(wù)躁染;或者使用dispatch_group_wait回到當前線程繼續(xù)向下執(zhí)行(會阻塞當前線程)鸣哀。
? ? ? ? 放入線程組的任務(wù)執(zhí)行完成了才會去調(diào)用dispatch_group_notify線程通知架忌,而如果在任務(wù)中還嵌套了異步任務(wù)吞彤,線程組不會管這個嵌套異步任務(wù)是否執(zhí)行完成,調(diào)用了這個任務(wù)就完成了叹放,因為是異步的就不會等執(zhí)行完成就繼續(xù)下一步了饰恕,一旦線程組第一層的任務(wù)都執(zhí)行完成了就會調(diào)用通知。如果將異步換成同步的井仰,就要等待嵌套任務(wù)執(zhí)行完成才會去通知埋嵌。
dispatch_group_notify
監(jiān)聽 group 中任務(wù)的完成狀態(tài),當所有的任務(wù)都執(zhí)行完成后俱恶,追加任務(wù)到 group 中雹嗦,并執(zhí)行任務(wù)。
- (void)groupNotify {
? ? NSLog(@"%@",[NSThread currentThread]);
? ? NSLog(@"begin");
? ? dispatch_group_t group = dispatch_group_create();
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? dispatch_group_async(group, queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? NSLog(@"111===%@",[NSThread currentThread]);
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? NSLog(@"222===%@",[NSThread currentThread]);
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? NSLog(@"333===%@",[NSThread currentThread]);
? ? });
? ? dispatch_group_notify(group, queue, ^{
? ? ? ? NSLog(@"notify");
? ? ? ? NSLog(@"notify===%@",[NSThread currentThread]);
? ? });
? ? NSLog(@"end");
}
輸出結(jié)果:
2018-11-23 10:17:32.570579+0800 OC-Swift[1732:40516] <NSThread: 0x600002913000>{number = 1, name = main}
2018-11-23 10:17:32.570755+0800 OC-Swift[1732:40516] begin
2018-11-23 10:17:32.570865+0800 OC-Swift[1732:40516] end
2018-11-23 10:17:33.576228+0800 OC-Swift[1732:41373] 222===<NSThread: 0x600002966040>{number = 10, name = (null)}
2018-11-23 10:17:33.576246+0800 OC-Swift[1732:41374] 333===<NSThread: 0x600002996540>{number = 11, name = (null)}
2018-11-23 10:17:33.576227+0800 OC-Swift[1732:40796] 111===<NSThread: 0x600002990c40>{number = 8, name = (null)}
2018-11-23 10:17:33.576692+0800 OC-Swift[1732:41373] notify
2018-11-23 10:17:33.576988+0800 OC-Swift[1732:41373] notify===<NSThread: 0x600002966040>{number = 10, name = (null)}
結(jié)果分析:
當所有任務(wù)都執(zhí)行完成之后合是,才執(zhí)行dispatch_group_notify 中的任務(wù)了罪。
在線程組中嵌套使用dispatch_async:
- (void)groupNotify {
? ? NSLog(@"%@",[NSThread currentThread]);
? ? NSLog(@"begin");
? ? dispatch_group_t group = dispatch_group_create();
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? dispatch_group_async(group, queue, ^{
? ? ? ? dispatch_async(queue, ^{
? ? ? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? ? ? NSLog(@"111===%@",[NSThreadcurrentThread]);
? ? ? ? });
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? dispatch_async(queue, ^{
? ? ? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? ? ? NSLog(@"222===%@",[NSThreadcurrentThread]);
? ? ? ? });
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? dispatch_async(queue, ^{
? ? ? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? ? ? NSLog(@"333===%@",[NSThreadcurrentThread]);
? ? ? ? });
? ? });
? ? dispatch_group_notify(group, queue, ^{
? ? ? ? NSLog(@"notify");
? ? ? ? NSLog(@"notify===%@",[NSThread currentThread]);
? ? });
}
輸出結(jié)果:
2018-11-23 10:54:36.377735+0800 OC-Swift[2129:57999] <NSThread: 0x6000019ab6c0>{number = 1, name = main}
2018-11-23 10:54:36.377940+0800 OC-Swift[2129:57999] begin
2018-11-23 10:54:36.378130+0800 OC-Swift[2129:58026] notify
2018-11-23 10:54:36.378367+0800 OC-Swift[2129:58026] notify===<NSThread: 0x6000019d50c0>{number = 3, name = (null)}
2018-11-23 10:54:37.383172+0800 OC-Swift[2129:58028] 222===<NSThread: 0x600001925f00>{number = 4, name = (null)}
2018-11-23 10:54:37.383191+0800 OC-Swift[2129:58025] 111===<NSThread: 0x600001928cc0>{number = 5, name = (null)}
2018-11-23 10:54:37.383249+0800 OC-Swift[2129:58027] 333===<NSThread: 0x600001925e40>{number = 6, name = (null)}
結(jié)果分析:
一旦線程組第一層的任務(wù)都執(zhí)行完成了就會調(diào)用通知。
在線程組中嵌套使用dispatch_async:
- (void)groupNotify {
? ? NSLog(@"%@",[NSThread currentThread]);
? ? NSLog(@"begin");
? ? dispatch_group_t group = dispatch_group_create();
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? dispatch_group_async(group, queue, ^{
? ? ? ? dispatch_sync(queue, ^{
? ? ? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? ? ? NSLog(@"111===%@",[NSThreadcurrentThread]);
? ? ? ? });
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? dispatch_sync(queue, ^{
? ? ? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? ? ? NSLog(@"222===%@",[NSThreadcurrentThread]);
? ? ? ? });
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? dispatch_sync(queue, ^{
? ? ? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? ? ? NSLog(@"333===%@",[NSThreadcurrentThread]);
? ? ? ? });
? ? });
? ? dispatch_group_notify(group, queue, ^{
? ? ? ? NSLog(@"notify");
? ? ? ? NSLog(@"notify===%@",[NSThread currentThread]);
? ? });
}
輸出結(jié)果:
2018-11-23 10:57:56.254579+0800 OC-Swift[2168:59624] <NSThread: 0x600003e49340>{number = 1, name = main}
2018-11-23 10:57:56.254720+0800 OC-Swift[2168:59624] begin
2018-11-23 10:57:57.257480+0800 OC-Swift[2168:59659] 333===<NSThread: 0x600003ec83c0>{number = 5, name = (null)}
2018-11-23 10:57:57.257486+0800 OC-Swift[2168:59660] 111===<NSThread: 0x600003ec8380>{number = 3, name = (null)}
2018-11-23 10:57:57.257480+0800 OC-Swift[2168:59658] 222===<NSThread: 0x600003e2dd00>{number = 4, name = (null)}
2018-11-23 10:57:57.257756+0800 OC-Swift[2168:59658] notify
2018-11-23 10:57:57.257924+0800 OC-Swift[2168:59658] notify===<NSThread: 0x600003e2dd00>{number = 4, name = (null)}
結(jié)果分析:
必須要等待嵌套任務(wù)執(zhí)行完成才會去通知聪全。
dispatch_group_wait
暫停當前線程(阻塞當前線程)泊藕,等待指定的 group 中的任務(wù)執(zhí)行完成后,才會往下繼續(xù)執(zhí)行难礼⊥拊玻或者等待timeout發(fā)生超時玫锋,當在超時時間timeout內(nèi)執(zhí)行完了所有的任務(wù)返回0,否則返回非0值。
- (void)groupWait {
? ? NSLog(@"%@",[NSThread currentThread]);
? ? NSLog(@"begin");
? ? dispatch_group_t group = dispatch_group_create();
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? dispatch_group_async(group, queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? NSLog(@"111===%@",[NSThread currentThread]);
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? NSLog(@"222===%@",[NSThread currentThread]);
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? NSLog(@"333===%@",[NSThread currentThread]);
? ? });
? ? dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
? ? NSLog(@"end");
}
輸出結(jié)果:
2018-11-23 10:21:14.961247+0800 OC-Swift[1821:43835] <NSThread: 0x600002796900>{number = 1, name = main}
2018-11-23 10:21:14.961411+0800 OC-Swift[1821:43835] begin
2018-11-23 10:21:15.962678+0800 OC-Swift[1821:43871] 333===<NSThread: 0x6000027e9180>{number = 3, name = (null)}
2018-11-23 10:21:15.962694+0800 OC-Swift[1821:43872] 222===<NSThread: 0x6000027ec000>{number = 5, name = (null)}
2018-11-23 10:21:15.962720+0800 OC-Swift[1821:43870] 111===<NSThread: 0x6000027ea080>{number = 4, name = (null)}
2018-11-23 10:21:15.962990+0800 OC-Swift[1821:43835] end
結(jié)果分析:
當所有任務(wù)執(zhí)行完成之后讼呢,才執(zhí)行dispatch_group_wait之后的操作撩鹿,會阻塞當前線程。
設(shè)定等待時間:
- (void)groupWait {
? ? NSLog(@"%@",[NSThread currentThread]);
? ? NSLog(@"begin");
? ? dispatch_group_t group = dispatch_group_create();
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? dispatch_group_async(group, queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? NSLog(@"111===%@",[NSThread currentThread]);
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];// 模擬耗時操作
? ? ? ? NSLog(@"222===%@",[NSThread currentThread]);
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:5];// 模擬耗時操作
? ? ? ? NSLog(@"333===%@",[NSThread currentThread]);
? ? });
? ? dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)));
? ? NSLog(@"end");
}
輸出結(jié)果:
2018-11-23 11:12:06.774259+0800 OC-Swift[2329:65999] <NSThread: 0x600003236980>{number = 1, name = main}
2018-11-23 11:12:06.774379+0800 OC-Swift[2329:65999] begin
2018-11-23 11:12:07.777851+0800 OC-Swift[2329:66031] 222===<NSThread: 0x60000325df80>{number = 3, name = (null)}
2018-11-23 11:12:07.777851+0800 OC-Swift[2329:66032] 111===<NSThread: 0x60000325e380>{number = 4, name = (null)}
2018-11-23 11:12:09.775667+0800 OC-Swift[2329:65999] end
2018-11-23 11:12:11.778701+0800 OC-Swift[2329:66030] 333===<NSThread: 0x6000032b4b00>{number = 5, name = (null)}
結(jié)果分析:
當超過設(shè)定的等待時間后悦屏,就會執(zhí)行dispatch_group_wait之后的操作三痰,不會等待任務(wù)組中未執(zhí)行完的任務(wù)執(zhí)行完成。
需要注意的:dispatch_group_wait是同步的所以不能放在主線程執(zhí)行窜管。
dispatch_group_enter散劫、dispatch_group_leave
dispatch_group_enter標志著一個任務(wù)追加到 group,執(zhí)行一次幕帆,相當于 group 中未執(zhí)行完畢任務(wù)數(shù)+1
dispatch_group_leave標志著一個任務(wù)離開了 group获搏,執(zhí)行一次,相當于 group 中未執(zhí)行完畢任務(wù)數(shù)-1失乾。
當 group 中未執(zhí)行完畢任務(wù)數(shù)為0的時候常熙,才會使dispatch_group_wait解除阻塞,或者執(zhí)行追加到dispatch_group_notify中的任務(wù)碱茁。
- (void)groupEnterAndLeave{
?? ? NSLog(@"%@",[NSThread currentThread]);
?? ? NSLog(@"begin");
? ? dispatch_group_t group = dispatch_group_create();
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? dispatch_group_enter(group);
? ? dispatch_async(queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];
? ? ? ? NSLog(@"111===%@",[NSThread currentThread]);
? ? ? ? dispatch_group_leave(group);
? ? });
? ? dispatch_group_enter(group);
? ? dispatch_async(queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];
? ? ? ? NSLog(@"222===%@",[NSThread currentThread]);
? ? ? ? dispatch_group_leave(group);
? ? });
? ? dispatch_group_enter(group);
? ? dispatch_async(queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];
? ? ? ? NSLog(@"333===%@",[NSThread currentThread]);
? ? ? ? dispatch_group_leave(group);
? ? });
? ? dispatch_group_notify(group, queue, ^{
? ? ? ? NSLog(@"notify");
? ? ? ? NSLog(@"notify===%@",[NSThread currentThread]);
? ? });
? ? NSLog(@"end");
}
輸出結(jié)果:
2018-11-23 14:34:24.784460+0800 OC-Swift[4127:148453] <NSThread: 0x600002bce880>{number = 1, name = main}
2018-11-23 14:34:24.784723+0800 OC-Swift[4127:148453] begin
2018-11-23 14:34:24.784877+0800 OC-Swift[4127:148453] end
2018-11-23 14:34:25.790320+0800 OC-Swift[4127:148487] 111===<NSThread: 0x600002b40040>{number = 5, name = (null)}
2018-11-23 14:34:25.790320+0800 OC-Swift[4127:148485] 222===<NSThread: 0x600002b40c00>{number = 4, name = (null)}
2018-11-23 14:34:25.790326+0800 OC-Swift[4127:148486] 333===<NSThread: 0x600002bbd080>{number = 3, name = (null)}
2018-11-23 14:34:25.790708+0800 OC-Swift[4127:148485] notify
2018-11-23 14:34:25.790986+0800 OC-Swift[4127:148485] notify===<NSThread: 0x600002b40c00>{number = 4, name = (null)}
結(jié)果分析:
當所有任務(wù)執(zhí)行完成之后裸卫,才執(zhí)行 dispatch_group_notify 中的任務(wù)。這里的dispatch_group_enter纽竣、dispatch_group_leave組合墓贿,其實等同于dispatch_group_async。
注意:如果使用上面兩個函數(shù)蜓氨,那么只有在任務(wù)管理組中的dispatch_group_enter和dispatch_group_leave都平衡的情況下dispatch_group_notify才會執(zhí)行聋袋,它們一般是成對出現(xiàn)的, 進入一次就得離開一次。也就是說穴吹,當離開和進入的次數(shù)相同時幽勒,就代表任務(wù)組完成了。如果enter比leave多港令,那就是沒完成啥容,如果leave調(diào)用的次數(shù)多了, 會崩潰的顷霹。
在上面dispatch_group_notify的例子中咪惠,在線程組中嵌套使用dispatch_async,發(fā)現(xiàn)一旦線程組第一層的任務(wù)都執(zhí)行完成了就會調(diào)用通知泼返。這里dispatch_group_enter和dispatch_group_leave就派上用場了硝逢,它們可以確保等待嵌套任務(wù)執(zhí)行完成才會去通知:
- (void)groupEnterAndLeave {
?? ? NSLog(@"%@",[NSThread currentThread]);
?? ? NSLog(@"begin");
? ? dispatch_group_t group = dispatch_group_create();
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? dispatch_group_enter(group);
? ? dispatch_async(queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];
? ? ? ? NSLog(@"111===%@",[NSThread currentThread]);
? ? ? ? dispatch_group_leave(group);
? ? });
? ? dispatch_group_enter(group);
? ? dispatch_group_async(group, queue, ^{
? ? ? ? dispatch_async(queue, ^{
? ? ? ? ? ? [NSThread sleepForTimeInterval:4];
? ? ? ? ? ? NSLog(@"222===%@",[NSThreadcurrentThread]);
? ? ? ? ? ? dispatch_group_leave(group);
? ? ? ? });
? ? });
? ? dispatch_group_enter(group);
? ? dispatch_async(queue, ^{
? ? ? ? [NSThread sleepForTimeInterval:1];
? ? ? ? NSLog(@"333===%@",[NSThread currentThread]);
? ? ? ? dispatch_group_leave(group);
? ? });
? ? dispatch_group_notify(group, queue, ^{
? ? ? ? NSLog(@"notify");
? ? ? ? NSLog(@"notify===%@",[NSThread currentThread]);
? ? });
? ? NSLog(@"end");
}
輸出結(jié)果:
2018-11-23 15:59:05.550556+0800 OC-Swift[5031:183263] begin
2018-11-23 15:59:05.550672+0800 OC-Swift[5031:183263] end
2018-11-23 15:59:06.553207+0800 OC-Swift[5031:183299] 111===<NSThread: 0x60000153ed40>{number = 3, name = (null)}
2018-11-23 15:59:06.553207+0800 OC-Swift[5031:183296] 333===<NSThread: 0x60000153ec00>{number = 4, name = (null)}
2018-11-23 15:59:09.550970+0800 OC-Swift[5031:183298] 222===<NSThread: 0x600001531880>{number = 5, name = (null)}
2018-11-23 15:59:09.551351+0800 OC-Swift[5031:183299] notify
2018-11-23 15:59:09.551803+0800 OC-Swift[5031:183299] notify===<NSThread: 0x60000153ed40>{number = 3, name = (null)}
結(jié)果分析:
嵌套任務(wù)執(zhí)行完成才會去通知。