假如现在有几组任务,我们并不关心每组中的各个任务的执行顺序,但是我们要求这几组任务按顺序分批进行,也就是说第一组任务全部执行之后,再启动第二组任务,以此类推。在这种情况下,我们使用 dispatch_barrier 函数将会非常高效,dispatch_barrier 函数又称作栅栏函数,顾名思义,就是像栅栏一样可以把不同任务分开。

在下面例子中,我们假设有两组任务,第一组包含任务 1 和任务 2,第二组包含任务 3 和任务 4,要求第一组任务执行完后再开始执行第二组任务:

NSLog(@"-- start --");// 创建一个并行队列
dispatch_queue_t queue = dispatch_queue_create("com.jarypan.gcdsummary", DISPATCH_QUEUE_CONCURRENT);// 向队列中追加任务
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task1 -- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task2 -- %@", [NSThread currentThread]);
});// 使用栅栏函数
dispatch_barrier_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"barrier task -- %@", [NSThread currentThread]);
});// 在栅栏函数后边继续追加任务
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task3 -- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task4 -- %@", [NSThread currentThread]);
});NSLog(@"-- end --");

运行后查看打印信息:

2019-09-22 01:09:31.383838+0800 GCDSummary[33672:1003194] -- start --
2019-09-22 01:09:31.384070+0800 GCDSummary[33672:1003194] -- end --
2019-09-22 01:09:32.388449+0800 GCDSummary[33672:1003251] task1 -- <NSThread: 0x60000154f100>{number = 4, name = (null)}
2019-09-22 01:09:32.388455+0800 GCDSummary[33672:1003252] task2 -- <NSThread: 0x600001574540>{number = 3, name = (null)}
2019-09-22 01:09:33.389078+0800 GCDSummary[33672:1003252] barrier task -- <NSThread: 0x600001574540>{number = 3, name = (null)}
2019-09-22 01:09:34.390192+0800 GCDSummary[33672:1003251] task4 -- <NSThread: 0x60000154f100>{number = 4, name = (null)}
2019-09-22 01:09:34.390226+0800 GCDSummary[33672:1003252] task3 -- <NSThread: 0x600001574540>{number = 3, name = (null)}

可以看到,task1、task2 行完成后,开始执行 dispatch_barrier_async 方法中的任务,之后追加的 task3 和 task4 是在 dispatch_barrier_async 方法中的任务执行完成后才开始执行的。

简而言之,在一个并发队列中,执行完栅栏前边的操作后,才执行栅栏操作,最后再执行栅栏后边的操作。

特别注意:

在使用栅栏函数时,使用自定义队列才有意义。如果使用的是串行队列,那么栅栏函数的作用将无法体现,所有任务会按照追加顺序依次执行;如果使用的是全局并发队列,那么栅栏函数的作用将仅仅是一个 dispatch_syncdispatch_async函数的作用(取决于你使用的是 dispatch_barrier_sync 还是 dispatch_barrier_async)。

下面我们针对 2 种情况做下测试:

1、使用串行队列:

NSLog(@"-- start --");// 创建一个串行队列
dispatch_queue_t queue = dispatch_queue_create("com.jarypan.gcdsummary", DISPATCH_QUEUE_SERIAL);// 向队列中追加任务
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task1 -- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task2 -- %@", [NSThread currentThread]);
});// 使用栅栏函数
dispatch_barrier_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"barrier task -- %@", [NSThread currentThread]);
});// 在栅栏函数后边继续追加任务
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task3 -- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task4 -- %@", [NSThread currentThread]);
});NSLog(@"-- end --");// 运行后的打印信息:
2019-09-24 16:25:34.531799+0800 GCDSummary[67542:1768993] -- start --
2019-09-24 16:25:34.531969+0800 GCDSummary[67542:1768993] -- end --
2019-09-24 16:25:35.533626+0800 GCDSummary[67542:1769035] task1 -- <NSThread: 0x60000348fbc0>{number = 3, name = (null)}
2019-09-24 16:25:36.535009+0800 GCDSummary[67542:1769035] task2 -- <NSThread: 0x60000348fbc0>{number = 3, name = (null)}
2019-09-24 16:25:37.540172+0800 GCDSummary[67542:1769035] barrier task -- <NSThread: 0x60000348fbc0>{number = 3, name = (null)}
2019-09-24 16:25:38.543857+0800 GCDSummary[67542:1769035] task3 -- <NSThread: 0x60000348fbc0>{number = 3, name = (null)}
2019-09-24 16:25:39.547243+0800 GCDSummary[67542:1769035] task4 -- <NSThread: 0x60000348fbc0>{number = 3, name = (null)}

通过打印信息可以看出,每个异步任务都相隔 1 秒时间(模拟的耗时操作时间),也就是说,此时的 dispatch_barrier_async 方法的作用相当于 dispatch_async 方法,在串行队列中依次执行任务,上一个任务完成后再执行后一个任务,这样就失去了 dispatch_barrier_async 方法的意义。

2、使用全局并发队列:

NSLog(@"-- start --");// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);// 向队列中追加任务
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task1 -- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task2 -- %@", [NSThread currentThread]);
});// 使用栅栏函数
dispatch_barrier_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"barrier task -- %@", [NSThread currentThread]);
});// 在栅栏函数后边继续追加任务
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task3 -- %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{[NSThread sleepForTimeInterval:1]; // 模拟耗时操作NSLog(@"task4 -- %@", [NSThread currentThread]);
});NSLog(@"-- end --");// 运行后的打印信息:
2019-09-24 16:14:36.724053+0800 GCDSummary[67393:1764449] -- start --
2019-09-24 16:14:36.724251+0800 GCDSummary[67393:1764449] -- end --
2019-09-24 16:14:37.727402+0800 GCDSummary[67393:1764502] barrier task -- <NSThread: 0x600001202140>{number = 6, name = (null)}
2019-09-24 16:14:37.727402+0800 GCDSummary[67393:1764500] task3 -- <NSThread: 0x600001208240>{number = 5, name = (null)}
2019-09-24 16:14:37.727419+0800 GCDSummary[67393:1764501] task2 -- <NSThread: 0x600001208280>{number = 7, name = (null)}
2019-09-24 16:14:37.727464+0800 GCDSummary[67393:1764499] task1 -- <NSThread: 0x60000120c3c0>{number = 3, name = (null)}
2019-09-24 16:14:37.727475+0800 GCDSummary[67393:1764504] task4 -- <NSThread: 0x60000123c780>{number = 4, name = (null)}

通过打印信息可以看出,此时 dispatch_barrier_async 方法无法控制队列中任务的执行顺序,本身的作用也和 dispatch_async 方法一样,所有任务包括 dispatch_barrier_async 方法中的任务都是并发执行,执行完成的顺序随机。

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

  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. Akamai CDN技术调研
  2. 登录文档服务器,服务器登录login
  3. arduino 呼吸灯_如何改善您的Arduino呼吸机:用于临时COVID-19呼吸机设计的RTS和SCS简介...
  4. I210网卡LINUX的mac,linux i210 网卡驱动解读
  5. python精要(81)-collections容器类型(1)-统计相同的值
  6. 收藏 | 人脸识别最新进展
  7. Autolayout的简单介绍和示例代码
  8. UnityShader14.1:透明效果实现(下)
  9. NCC2105关于分管领导审批流设置另一方法
  10. java web程序设计答案郭克华_清华大学出版社郭克华JavaWeb程序设计上机习题答案及解析.doc...
  11. 真假Kingston U盘识别
  12. 实习生也容易上手的ui框架
  13. 【程序人生】机灵鹤六月份的月度总结
  14. 【招聘】极限网络全国招聘,海量岗位职等你来
  15. SP4354 TWINSNOW - Snowflakes
  16. 学VC,我想对自己说......
  17. SpringCloud | 第二章: 注册中心 Eureka
  18. 常用校验算法(累加和、异或和)
  19. 【单片机毕业设计】【mcuclub-106】智能晾衣架 | 多功能晾衣架【仿真设计】
  20. C++图形用户界面开发框架Qt 6.x入门级教程 - 开发工具简介

热门文章

  1. 十九. 用户注册 --- 短信验证码实现 2021-04-16
  2. 瑞芯微rv1126/1109软硬件解压缩对比---附:关于内存对齐的那些事
  3. 北航大学计算机学院新媒体艺术系,本科优秀毕业论文参考-北航新媒体与艺术学院-北京航空航天大学.doc...
  4. java身份证实名认证
  5. 【157天】尚学堂高琪Java300集视频精华笔记(126)
  6. 测试一拳多少公斤的软件,李小龙一拳能打出400公斤,手里双节棍有多少力量,测试后难以置信...
  7. winsxs目录清理工具
  8. 英国高端SPA级奢养护肤品牌EVE LOM相继入驻成都IFS、北京连卡佛;FILA斐乐携手梵高博物馆推出全新联名系列 | 知消...
  9. 善于做“加减法”的百分点科技 成就数据智能的先行者
  10. An invalid domain [] was specified for this cookie问题解决