平时在进行多线程处理任务时,有时候希望多个任务之间存在着一种联系,希望在所有的任务执行完后做一些总结性处理。
那么就可以将多个任务放在一个任务组中进行统一管理。通过监听组内所有任务执行情况来做相应处理。
常用函数:
dispatch_group_create():创建一个group组。
dispatch_group_async(group, queue, block):将任务添加到queue队列,并被group组管理。
dispatch_group_enter(group):添加任务组中为执行完毕的任务数,声明dispatch_group_enter(group)下面的任务由group组管理,group组的任务数+1。当未执行完毕任务数为0时,才会使dispatch_group_wait解除阻塞和dispatch_group_notify的block执行,即:通知group,下边的任务要放到group中执行了。
dispatch_group_leave(group):相应的任务执行完成,group组的任务数-1。减少任务组中未执行完毕的任务数,执行一次,未执行完毕的任务数减1,注dispatch_group_enter和dispatch_group_leave要匹配,不然系统会认为group任务没有执行完毕。即:通知group,任务完成了,该任务要从group中移除了。
dispatch_group_wait(group, DISPATCH_TIME_FOREVER):在任务完成或超时都会调用;完成是enter和leave一样多),当前线程暂停,等待dispatch_group_wait(group1, DISPATCH_TIME_FOREVER)上面的任务执行完成后,线程才继续执行。dispatch_group_wait 设置等待时间,在等待时间结束后,如果还没有执行完任务组,则返回。返回0代表执行成功,非0则执行失败
dispatch_group_notify(group, queue,block):监听group组中任务的完成状态,当所有的任务都执行完成后,触发block块,执行总结性处理。不管是不是超时,只要任务完成,就会掉,不管是不是超时。
注:
1》dispatch_group_enter 和 dispatch_group_leave 一般是成对出现的, 进入一次,就得离开一次。也就是说,当离开和进入的次数相同时,就代表任务组完成了。如果enter比leave多,那就是没完成,会阻塞当前线程,如果leave调用的次数错了, 会崩溃;这两个方法显示的讲任务组中的任务未执行完毕的任务数目加减1,这种方式用在不使用dispatch_group_async来提交任务,注意:这两个函数要配合使用,有enter要有leave,这样才能保证功能完整实现。也可以用这对函数来让一个闭包关联多个Group。
2》dispatch_group_wait和dispatch_group_notify可以监听任务组内任务的执行情况。监听group组中任务的完成状态,当所有的任务都执行完成后,触发block块,执行总结性处理。
作用:
需要开启多个线程执行任务,例如有5张以下加入是3张图片需要异步下载,等3张图片下载完后需要合并成一张图片的操作,时需要group。(这里为么说是5张以下呢,因为开线程需要消耗cpu,开太多会造成卡顿等现象,最多开五条线程,如果下载的图片很多,例如100张,那我们就要用信号量dispatch_semaphore 来调度任务和线程)
分析:因为需要合并成一张图片,所以必须等三张图片全下载完才能执行合并操作,所以需要用到dispatch_group来对下载情况做处理。
使用:group使用的时候一般有两种组合形式:
1》dispatch_group_async方式:
dispatch_group_async(group, queue, block); //将任务添加到queue队列,并由group管理
dispatch_group_notify(group, queue, block);
2》enter与leave方式:
dispatch_group_enter(group);//将下边的任务由group管理
dispatch_group_leave(group);//任务完成,将任务从group移除
dispatch_group_notify(group, queue,block);
方式一:
{
dispatch_group_t asyncAsyncGroup = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(asyncAsyncGroup, queue, ^{
dispatch_async(queue, ^{
sleep(10);
NSLog(@"第一个任务");
});
});
dispatch_group_async(asyncAsyncGroup, queue, ^{
dispatch_async(queue, ^{
sleep(1);
NSLog(@"第二个任务");
});
});
dispatch_group_notify(asyncAsyncGroup, queue, ^{
NSLog(@"执行完毕了");
});
}
打印:
2018-10-18 16:56:23.501176+0800 dispatch_group[50937:2436276] 执行完毕了
2018-10-18 16:56:24.501235+0800 dispatch_group[50937:2436278] 第二个任务
2018-10-18 16:56:33.501669+0800 dispatch_group[50937:2436277] 第一个任务
方式二:
{
dispatch_group_t group = dispatch_group_create();
// dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(3);
NSLog(@"子线程中的子线程1");
dispatch_group_leave(group);
});
});
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
sleep(2);
NSLog(@"子线程中的子线程2");
dispatch_group_leave(group);
});
});
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"所有线程执行完毕");
});
}
打印:
2018-10-18 16:57:56.250547+0800 dispatch_group[50968:2438605] 子线程中的子线程2
2018-10-18 16:57:57.250830+0800 dispatch_group[50968:2438607] 子线程中的子线程1
2018-10-18 16:57:57.251054+0800 dispatch_group[50968:2438607] 所有线程执行完毕
以上两种方式都是模拟任务block内为异步操作的情况,方式一先执行的dispatch_group_notify里的代码,后执行的dispatch_group_async里的任务代码,这与我们的初衷相违背。如果任务block内为同步操作时,则无论哪种方式都不会出现这种状况。这也是dispatch_group的一个坑人的地方。我们在使用dispatch_group时一般都是想异步执行任务,所以,一定要注意这个坑
另外,还有dispatch_group_wait的使用,也提现在代码里了,可以任意修改wai里的时间,例如小于任务一的睡眠时间,大于任务一+任务二的睡眠时间总和,查看打印的变化,理解wait的作用。
代码:https://download.csdn.net/download/denggun12345/10730166