GCD 队列组:dispatch_group
有时候我们会有这样的需求:分别异步执行多个耗时任务,当多个耗时任务都执行完毕后,再回到指定线程执行任务。这时候我们可以用到 GCD 的队列组。调用队列组的dispatch_group_async先把任务放到队列中,然后将队列放入队列组中。或者使用队列组的dispatch_group_enter、dispatch_group_leave组合来实现。调用队列组的dispatch_group_notify回到指定线程执行任务;或者使用dispatch_group_wait回到当前线程继续向下执行(会阻塞当前线程)。
放入线程组的任务执行完成了才会去调用dispatch_group_notify线程通知,而如果在任务中还嵌套了异步任务,线程组不会管这个嵌套异步任务是否执行完成,调用了这个任务就完成了,因为是异步的就不会等执行完成就继续下一步了,一旦线程组第一层的任务都执行完成了就会调用通知。如果将异步换成同步的,就要等待嵌套任务执行完成才会去通知。
dispatch_group_notify
监听 group 中任务的完成状态,当所有的任务都执行完成后,追加任务到 group 中,并执行任务。
- (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");
}
输出结果:
2018-11-23 10:17:32.570579+0800 OC-Swift[1732:40516]
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===
2018-11-23 10:17:33.576246+0800 OC-Swift[1732:41374] 333===
2018-11-23 10:17:33.576227+0800 OC-Swift[1732:40796] 111===
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===
结果分析:
当所有任务都执行完成之后,才执行dispatch_group_notify 中的任务。
在线程组中嵌套使用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]);
});
}
输出结果:
2018-11-23 10:54:36.377735+0800 OC-Swift[2129:57999]
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===
2018-11-23 10:54:37.383172+0800 OC-Swift[2129:58028] 222===
2018-11-23 10:54:37.383191+0800 OC-Swift[2129:58025] 111===
2018-11-23 10:54:37.383249+0800 OC-Swift[2129:58027] 333===
结果分析:
一旦线程组第一层的任务都执行完成了就会调用通知。
在线程组中嵌套使用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]);
});
}
输出结果:
2018-11-23 10:57:56.254579+0800 OC-Swift[2168:59624]
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===
2018-11-23 10:57:57.257486+0800 OC-Swift[2168:59660] 111===
2018-11-23 10:57:57.257480+0800 OC-Swift[2168:59658] 222===
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===
结果分析:
必须要等待嵌套任务执行完成才会去通知。
dispatch_group_wait
暂停当前线程(阻塞当前线程),等待指定的 group 中的任务执行完成后,才会往下继续执行。或者等待timeout发生超时,当在超时时间timeout内执行完了所有的任务返回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");
}
输出结果:
2018-11-23 10:21:14.961247+0800 OC-Swift[1821:43835]
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===
2018-11-23 10:21:15.962694+0800 OC-Swift[1821:43872] 222===
2018-11-23 10:21:15.962720+0800 OC-Swift[1821:43870] 111===
2018-11-23 10:21:15.962990+0800 OC-Swift[1821:43835] end
结果分析:
当所有任务执行完成之后,才执行dispatch_group_wait之后的操作,会阻塞当前线程。
设定等待时间:
- (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");
}
输出结果:
2018-11-23 11:12:06.774259+0800 OC-Swift[2329:65999]
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===
2018-11-23 11:12:07.777851+0800 OC-Swift[2329:66032] 111===
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===
结果分析:
当超过设定的等待时间后,就会执行dispatch_group_wait之后的操作,不会等待任务组中未执行完的任务执行完成。
需要注意的:dispatch_group_wait是同步的所以不能放在主线程执行。
dispatch_group_enter、dispatch_group_leave
dispatch_group_enter标志着一个任务追加到 group,执行一次,相当于 group 中未执行完毕任务数+1
dispatch_group_leave标志着一个任务离开了 group,执行一次,相当于 group 中未执行完毕任务数-1。
当 group 中未执行完毕任务数为0的时候,才会使dispatch_group_wait解除阻塞,或者执行追加到dispatch_group_notify中的任务。
- (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");
}
输出结果:
2018-11-23 14:34:24.784460+0800 OC-Swift[4127:148453]
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===
2018-11-23 14:34:25.790320+0800 OC-Swift[4127:148485] 222===
2018-11-23 14:34:25.790326+0800 OC-Swift[4127:148486] 333===
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===
结果分析:
当所有任务执行完成之后,才执行 dispatch_group_notify 中的任务。这里的dispatch_group_enter、dispatch_group_leave组合,其实等同于dispatch_group_async。
注意:如果使用上面两个函数,那么只有在任务管理组中的dispatch_group_enter和dispatch_group_leave都平衡的情况下dispatch_group_notify才会执行,它们一般是成对出现的, 进入一次就得离开一次。也就是说,当离开和进入的次数相同时,就代表任务组完成了。如果enter比leave多,那就是没完成,如果leave调用的次数多了, 会崩溃的。
在上面dispatch_group_notify的例子中,在线程组中嵌套使用dispatch_async,发现一旦线程组第一层的任务都执行完成了就会调用通知。这里dispatch_group_enter和dispatch_group_leave就派上用场了,它们可以确保等待嵌套任务执行完成才会去通知:
- (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");
}
输出结果:
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===
2018-11-23 15:59:06.553207+0800 OC-Swift[5031:183296] 333===
2018-11-23 15:59:09.550970+0800 OC-Swift[5031:183298] 222===
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===
结果分析:
嵌套任务执行完成才会去通知。