GCD梳理与总结-常用API操练
时间:2022-07-28
本文章向大家介绍GCD梳理与总结-常用API操练,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
- 延时执行(dispatch_after) 需要注意的是:dispatch_after函数并不是在指定时间之后才开始执行处理,而是在指定时间之后将任务追加到队列中。严格来说,这个时间并不是绝对准确的,但想要大致延迟执行任务,dispatch_after函数是很有效。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后异步追加任务代码到主队列 NSLog(@"----执行任务---当前线程%@",[NSThread currentThread]); });复制代码
- 只执行一次(dispatch_once) 通常在创建单例时使用,多线程环境下也能保证线程安全
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"----只执行一次的任务---当前线程%@",[NSThread currentThread]); });复制代码
- 重复执行(dispatch_apply) 快速遍历方法,可以替代for循环的函数。dispatch_apply按照指定的次数将指定的任务追加到指定的队列中,并等待全部队列执行结束。你可以把他理解成for循环遍历,其优势是可以充分利用多核的性能。
//并发队列 dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //串行队列 dispatch_queue_t queue = dispatch_queue_create("com.test.testQueue", DISPATCH_QUEUE_SERIAL); //你可以试试并发和串行的区别 dispatch_apply(10, globalQueue, ^(size_t index) { NSLog(@"执行第%zd次的任务,%@",index,[NSThread currentThread]); [NSThread sleepForTimeInterval:1]; });复制代码
- 队列组(dispatch_group) 比如当我们遇到需要异步下载3张图片,都下载完之后再拼接成一个整图的时候,就需要用到gcd队列组。 dispatch_group_enter 标志着一个任务追加到 group,执行一次,相当于 group 中未执行完毕任务数+1 dispatch_group_leave 标志着一个任务离开了 group,执行一次,相当于 group 中未执行完毕任务数-1。 当 group 中未执行完毕任务数为0的时候,才会使dispatch_group_wait解除阻塞,以及执行追加到dispatch_group_notify中的任务。
//创建队列组 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:2]; NSLog(@"执行第一个任务"); dispatch_group_leave(group); }); dispatch_group_enter(group); dispatch_async(queue, ^{ // 第二个任务 [NSThread sleepForTimeInterval:2]; NSLog(@"执行第二个任务"); dispatch_group_leave(group); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"执行最后的汇总任务"); }); 复制代码
- 信号量(dispatch_semaphore) 用来设置当前队列的最大并发数。 信号量就3个方法,1创建信号数量,2wait,3signal。信号量就类似交通信号灯。 dispatch_semaphore_wait判读当前信号量。为0则红灯禁止通行,等待信号量大于0后放行。放行后对信号量-1; dispatch_semaphore_signal与wait成对出现。表示任务已结束。对信号量+1;
//创建信号量为2 dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); //全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //任务1 dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"----开始执行第一个任务---"); [NSThread sleepForTimeInterval:2]; NSLog(@"----结束执行第一个任务---",); dispatch_semaphore_signal(semaphore); }); //任务2 dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"----开始执行第二个任务---"); [NSThread sleepForTimeInterval:1]; NSLog(@"----结束执行第二个任务---"); dispatch_semaphore_signal(semaphore); }); //任务3 dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"----开始执行第三个任务---",); [NSThread sleepForTimeInterval:2]; NSLog(@"----结束执行第三个任务---"); dispatch_semaphore_signal(semaphore); });复制代码
- 栅栏(dispatch_barrier) 在栅栏前放入队列的操作执行完后,再执行栅栏后放入队列的操作。当然也可以用Dispatch Group实现相同功能,只是比较而言,dispatch_barrier_async会更加顺滑。需要注意的是:使用的队列应该是你自己创建的并发队列。不可以是系统队列或者串行队列,具体原因,读者可以思考一下。
//全局并发队列 dispatch_queue_t queue = dispatch_queue_create("com.test.testQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"栅栏前的任务"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"栅栏前的任务"); }); //栅栏 dispatch_barrier_async(queue, ^{ // 等待处理 [NSThread sleepForTimeInterval:2]; NSLog(@"-栅栏等待-"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"栅栏后的任务"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"栅栏后的任务"); });复制代码
- 挂起(dispatch_suspend)、恢复(dispatch_resume)队列 简单来说,就是可以暂停、恢复队列上的任务。但是这里的“挂起”,并不能保证可以立即停止队列上正在运行的任务,也就是如果挂起之前已经有队列中的任务在进行中,那么该任务依然会被执行完毕
//串行队列 dispatch_queue_t queue = dispatch_queue_create("com.test.testQueue", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{ // 执行第一个任务 NSLog(@"----执行第一个任务---"); }); dispatch_async(queue, ^{ // 执行第二个任务 NSLog(@"开始执行第二个任务"); [NSThread sleepForTimeInterval:5]; NSLog(@"结束执行第二个任务"); }); dispatch_async(queue, ^{ // 执行第三个任务 NSLog(@"开始执行第三个任务"); [NSThread sleepForTimeInterval:5]; NSLog(@"结束执行第三个任务"); }); //此时发现意外情况,挂起队列 NSLog(@"suspend"); dispatch_suspend(queue); //挂起3秒之后,恢复正常 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //恢复队列 NSLog(@"3秒后恢复resume"); dispatch_resume(queue); });复制代码
定时器 GCD的定时器比NSTimer有更高的进度,而且避免了NSTimer的三大缺陷(RunLoop,不能跨越线程操作,内存泄漏风险)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建定时器
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//构建参数。设置从何时开始/设置时间间隔
dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, 0* NSEC_PER_SEC), 1.0 * NSEC_PER_SEC, 0);
//要执行的时间
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"多久打印一次");
});
//运行GSD
dispatch_resume(self.timer);
//取消定时器
//dispatch_cancel(self.timer); self.timer = nil;复制代码
总结
本节我们主要简单的梳理了GCD的一些实用API,可以发现这些API是纯c语言的,并且相关API繁多,在实际编码过程中即使有代码提示,往往编码效率还是比较慢的,造成一定的使用门槛。当然,你也通过自定义代码块来提升效率。
- 使用sysbench压力测试MySQL(三)(r12笔记第6天)
- 解决IE响应式的解决方案css3-mediaqueries.js不生效问题
- MySQL传输表空间小结(r12笔记第2天)
- swingbench压测Oracle小记(r12笔记第20天)
- 分享最近对网站外链跳转页面代码的一些改善
- swingbench压测Oracle小记(r12笔记第19天)
- Oracle闪回原理测试(三)(r12笔记第16天)
- 利用JS生成二维码图片,优化WEB性能及页面加载速度
- Go语言的指针 & *
- MySQL中的double write(二)(r12笔记第17天)
- 论Go语言中goroutine的使用
- WordPress发布文章同步到新浪微博失败的问题解决与分享
- 压测工具swingbench和sysbench对比(r12笔记第13天)
- 解决WordPress4.4.1不支持图片暗箱问题,Begin主题适用
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 排序算法之快速排序
- 干货 | Oracle数据库操作命令大全,满满的案例供你理解,收藏!
- 【2万字长文】深入浅出主流的几款小程序跨端框架原理
- 关于动态规划的练习题
- Linux笔记
- 使用OpenCV和Python计算视频中的总帧数
- HDOJ 1087 (JAVA实现 最大上升子序列和dp)
- JavaSE笔记
- [译]Gas 优化 - 如何优化存储
- Codeforces Round #613 (Div. 2) C. Fadi and LCM
- N皇后问题(DFS)
- [译]区块链民主 - 如何开发通过投票运行的合约
- java安全编码指南之:异常处理
- java安全编码指南之:死锁dead lock
- java安全编码指南之:方法编写指南