在实际开发中,我们经常会遇到这样的问题:有几个不同的任务,当所有任务完成后需要根据这些任务的结果去执行下一步操作(例如:下载多张图片,全部下载后进行拼接并显示出来)。我们利用上边刚刚讲过的 dispatch_barrier 方法或许可以达到此类目的,但下边要讲的 dispatch_group 相关方法才更适合解决类似问题。

在编写测试代码之前,我们还要了解一下 dispatch_group_notify

dispatch_group_notify

dispatch_group_notify 可以监听 group 中所有任务的完成状态,当所有任务都执行完成后,会追加任务到 group 中,并执行该任务。下面我们通过具体示例来详细了解 dispatch_group 的使用方法:

NSLog(@"-- begin --");// 创建一个分组
dispatch_group_t group = dispatch_group_create();// 创建一个并发队列
dispatch_queue_t queue = dispatch_queue_create("com.jarypan.gcdsummary", DISPATCH_QUEUE_CONCURRENT);// 向并发队列 queue 中追加任务并添加到分组 group 中
dispatch_group_async(group, queue, ^{[NSThread sleepForTimeInterval:1];NSLog(@"task1 -- %@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{[NSThread sleepForTimeInterval:1];NSLog(@"task2 -- %@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{[NSThread sleepForTimeInterval:1];NSLog(@"task3 -- %@", [NSThread currentThread]);
});// 监听 group 中所有任务的完成状态
dispatch_group_notify(group, dispatch_get_main_queue(), ^{[NSThread sleepForTimeInterval:2];NSLog(@"all tasks are finished -- %@", [NSThread currentThread]);
});NSLog(@"-- end --");

首先,我们创建了一个分组(dispatch_group_t 类型),该分组用来添加一系列的任务;

然后,我们创建了一个并发队列,该并发队列用于接收后续的异步任务(GCD 中的任务必须追加到具体的队列中才能执行);

接着,我们利用 dispatch_group_async 方法将任务追加到并发队列中,并同时添加到分组中,完成了多个任务的异步封装;

最后,我们利用监听函数 dispatch_group_notify 来监听分组中所有任务的完成状态,一旦所有任务执行结束,就会自动追加一个任务到分组中,并在指定的队列中执行任务。

对于上面的代码,这个自动追加到分组中的任务就是:

[NSThread sleepForTimeInterval:2];
NSLog(@"all tasks are finished -- %@", [NSThread currentThread]);

而这个指定的队列就是主队列(dispatch_get_main_queue() 方法获取的主队列)。

运行后查看打印信息:

2019-09-23 00:43:35.344343+0800 GCDSummary[41564:1184001] -- begin --
2019-09-23 00:43:35.344555+0800 GCDSummary[41564:1184001] -- end --
2019-09-23 00:43:36.345277+0800 GCDSummary[41564:1184044] task2 -- <NSThread: 0x6000033fcec0>{number = 3, name = (null)}
2019-09-23 00:43:36.345278+0800 GCDSummary[41564:1184043] task1 -- <NSThread: 0x6000033f7600>{number = 4, name = (null)}
2019-09-23 00:43:36.345282+0800 GCDSummary[41564:1184041] task3 -- <NSThread: 0x6000033fcf00>{number = 5, name = (null)}
2019-09-23 00:43:38.346901+0800 GCDSummary[41564:1184001] all tasks are finished -- <NSThread: 0x60000339e900>{number = 1, name = main}

可以看到,3 个任务都在已创建的子线程 queue 中执行,并且所有任务执行完毕后,才开始执行 dispatch_group_notify 中追加的任务,并且追加的任务是在指定的主线程中执行的。

对比 dispatch_barrier 方法,我们发现,dispatch_group 更适合用于多任务监听,dispatch_group 不但加入了分组的概念,而且在多任务完成后提供了更加灵活的方法方便用户指定一个队列执行要追加的任务。

dispatch_group_wait

dispatch_group_waitdispatch_group_notify 的作用相似,也是等待 group 中的任务全部执行完成后再进行下面的操作,但 dispatch_group_wait 并不能追加任务到 group 中,而且还会阻塞当前线程

NSLog(@"-- begin --");// 创建一个分组
dispatch_group_t group = dispatch_group_create();// 创建一个并发队列
dispatch_queue_t queue = dispatch_queue_create("com.jarypan.gcdsummary", DISPATCH_QUEUE_CONCURRENT);// 向并发队列 queue 中追加任务并添加到分组 group 中
dispatch_group_async(group, queue, ^{[NSThread sleepForTimeInterval:1];NSLog(@"task1 -- %@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{[NSThread sleepForTimeInterval:1];NSLog(@"task2 -- %@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{[NSThread sleepForTimeInterval:1];NSLog(@"task3 -- %@", [NSThread currentThread]);
});// 阻塞当前线程直到 group 中的所有任务执行完毕
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);NSLog(@"-- end --");

运行后查看打印信息:

2019-09-23 01:22:00.391770+0800 GCDSummary[42047:1199538] -- begin --
2019-09-23 01:22:01.393350+0800 GCDSummary[42047:1199581] task3 -- <NSThread: 0x6000010044c0>{number = 3, name = (null)}
2019-09-23 01:22:01.393334+0800 GCDSummary[42047:1199580] task2 -- <NSThread: 0x60000103bac0>{number = 5, name = (null)}
2019-09-23 01:22:01.393365+0800 GCDSummary[42047:1199579] task1 -- <NSThread: 0x60000103ba00>{number = 4, name = (null)}
2019-09-23 01:22:01.393772+0800 GCDSummary[42047:1199538] -- end --

可以看到,dispatch_group_wait 阻塞了当前线程,直到 group 中的所有任务执行完成,代码才继续向下进行(打印 -- end --),所以在主线程中使用 dispatch_group_wait 十分危险。在确实需要使用该方法时,我们一般会将整个 group 的操作放到一个异步执行的子线程中,这样当前线程等待就不会影响主线程中的操作。

dispatch_group_enter & dispatch_group_leave

dispatch_group_enter 标志着一个任务追加到 group 中,相当于 group 中未执行完毕任务数 +1。

dispatch_group_leave 标志着一个任务离开了 group,执行一次,相当于 group 中未执行完毕任务数 -1。

当 group 中未执行完毕任务数为 0 时,才会执行追加到 dispatch_group_notify 中的任务,或者使 dispatch_group_wait 解除当前线程的阻塞。所以,dispatch_group_enter 和 dispatch_group_leave 一定要成对出现

NSLog(@"-- begin --");// 创建一个分组
dispatch_group_t group = dispatch_group_create();// 创建一个并发队列
dispatch_queue_t queue = dispatch_queue_create("com.jarypan.gcdsummary", DISPATCH_QUEUE_CONCURRENT);// 将任务添加到分组中
dispatch_group_enter(group);
// 将任务追加到并发队列中
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1];NSLog(@"task1 -- %@", [NSThread currentThread]);// 将任务从分组中移除dispatch_group_leave(group);
});dispatch_group_enter(group);
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1];NSLog(@"task2 -- %@", [NSThread currentThread]);dispatch_group_leave(group);
});dispatch_group_enter(group);
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1];NSLog(@"task3 -- %@", [NSThread currentThread]);dispatch_group_leave(group);
});// 阻塞当前线程直到 group 中的所有任务执行完毕
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);NSLog(@"-- end --");

运行后查看打印信息:

2019-09-23 01:42:26.091738+0800 GCDSummary[42332:1208751] -- begin --
2019-09-23 01:42:27.097094+0800 GCDSummary[42332:1208797] task2 -- <NSThread: 0x60000144c040>{number = 3, name = (null)}
2019-09-23 01:42:27.097099+0800 GCDSummary[42332:1208798] task3 -- <NSThread: 0x60000146b900>{number = 5, name = (null)}
2019-09-23 01:42:27.097089+0800 GCDSummary[42332:1208795] task1 -- <NSThread: 0x60000142ec00>{number = 4, name = (null)}
2019-09-23 01:42:27.097396+0800 GCDSummary[42332:1208751] -- end --

可以看到,当分组中的所有任务执行完成后,才解除了 dispatch_group_wait 对当前线程的阻塞。这里的 dispatch_group_enterdispatch_group_leave 组合,等同于 dispatch_group_async 方法。

GCD中dispatch_group的使用方法相关推荐

  1. 计时器延迟 NSTimer和CADisplaylink GCD中的延迟

    1,NStimer时间间隔比较大,大于1秒: CADisplayLink 时间间隔比较小,0.01秒: 2,创建启动计时器: [NSTimer scheduledTimeInterval:0.5 ta ...

  2. GCD中的队列与任务

    一.简介: Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法.它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统.它是一个在线程池模式的 ...

  3. stream map方法_Java Stream中map和flatMap方法

    最近看到一篇讲stream语法的文章,学习Java中map()和flatMap()方法之间的区别. 虽然看起来这两种方法都做同样的事情,都是做的映射操作,但实际上差之毫厘谬以千里. 通过演示Demo中 ...

  4. java中json重复数据结构_JS实现去除数组中重复json的方法示例

    本文实例讲述了JS实现去除数组中重复json的方法.分享给大家供大家参考,具体如下: var array = [{"name":"123"},{"na ...

  5. 继承实现的原理、子类中调用父类的方法、封装

    一.继承实现的原来 1.继承顺序 Python的类可以继承多个类.继承多个类的时候,其属性的寻找的方法有两种,分别是深度优先和广度优先. 如下的结构,新式类和经典类的属性查找顺序都一致.顺序为D--- ...

  6. 浅谈在ASP.NET中数据有效性校验的方法

    作者:未知 作为一名程序员,一定要对自己编写的程序的健壮性负责,因此数据的校验无论在商业逻辑还是系统实现都是必不可少的部分. 我这里总结了一种自认为比较不错的asp.net(C#)的数据校验方法,如大 ...

  7. JavaScript文件中调用AngularJS内部方法或改变$scope变量

    需要在其他JavaScript文件中调用AngularJS内部方法或改变$scope变量,同时还要保持双向数据绑定: 首先获取AngularJS application: 方法一:通过controll ...

  8. D3D中简单的截图方法 (转)

    [ZT]D3D中简单的截图方法 试了下,果然可以. 在渲染完所有东东后(Present之前) 获得BackBuffer表面 然后用D3DX的函数保存 void ScreenShot (char *fi ...

  9. hibernate4中取得connection的方法

    在hibernate3中,使用了c3p0连接池,尝试了多种办法取得connection对象,以下两种可以使用. Java代码  Connection conn; // 方法1:hibernate4中将 ...

  10. c#中接口的使用方法图解_C#图解教程 第十五章 接口

    接口 什么是接口 接口是指定一组函数成员而不实现它们的引用类型.所以只能类和结构来实现接口. 这种描述比较抽象,直接来看个示例. 下例中,Main方法创建并初始化了一个CA类的对象,并将该对象传递给P ...

最新文章

  1. FFmpeg中编码类型为rawvideo无须解码直接显示测试代码
  2. 高效读CV论文法则:先在GitHub上立Flag!| 资源
  3. python电影情感评论分析_Kaggle电影评论情感分析
  4. smarty模板截取字符串乱码问题完美解决```````
  5. 计算矩阵连乘积(动态规划)
  6. vue中的if判断和for循环语句
  7. BZOJ 1800: [Ahoi2009]fly 飞行棋( 枚举 )
  8. 牛客-沙漠点列【tarjan】
  9. Python str字符串常用到的函数
  10. StringUtils,FileUtils,PropertiesUtils,DataBaseUtils
  11. C#学习笔记——.NET
  12. .NET Framework-多线程网络编程
  13. 联想计算机怎样分区,怎么给联想笔记本硬盘分区【图文】
  14. 【一起学Rust】Rust介绍与开发环境搭建
  15. 记成功坚持学习英语45天截点—Darren
  16. 在运行java程序时出现 Error: could not open c:\program Files\Java\jre6\lib\amd64\jvm.cfg'
  17. 镁光闪存颗粒对照表_海力士、南亚、镁光内存颗粒编码解析,妈妈再也不用担心你买内存条了...
  18. 阿里云物联网IOT平台使用案例教程(模拟智能设备)
  19. Robocup 仿真2D 学习笔记(三)最初的改进1
  20. 程序黑框中出现:(路径)用作为当前目录的以上路径启动了 CMD.EXE。 UNC 路径不受支持,默认值设为 Windows 目录。

热门文章

  1. java8新增特性一:lambda表达式
  2. stc单片机c语言程序头文件(stc12c5a60s2.h,STC12C5A60S2单片机头文件
  3. 中国顶级CEO经典语录
  4. oracle append parallel,大量数据快速插入方法探究[nologging+parallel+append]
  5. 服务器带宽打开网页很慢,网速快但是打开网页慢是怎么回事 浏览器打开网页慢的解决办法汇总...
  6. macbook打开网页慢解决办法
  7. 合唱队形java_动态规划练习题-合唱队形
  8. C盘空间不足,释放C盘空间
  9. 前段时间 qq大战 360..
  10. 呕心沥血互联网产品经理巨作