多线程--GCD的基本用法
---恢复内容开始---
GCD
GCD的优势
GCD是苹果公司为多核的并行运算提出的解决方案
GCD会自动利用更多的CPU内核(比如双核、四核)
- GCD会自动将队列中的任务取出,放到对应的线程中执行
- 任务的取出遵循队列的FIFO原则:先进先出,后进后出
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
/********************************创建串行queue队列********************************/
DISPATCH_QUEUE_SERIAL这里换成NULL也是创建串行队列
dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
/********************************第一次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"A------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"B------%@", [NSThread currentThread]);}});dispatch_async(queue, ^{
/********************************第二次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"C------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"D------%@", [NSThread currentThread]);}});dispatch_release(queue);NSLog(@"E--------%@", [NSThread currentThread]);
}
输出结果:
2016-03-29 21:28:50.991 test1[1021:62256] E--------<NSThread: 0x7fcaa0601a00>{number = 1, name = main}
2016-03-29 21:28:50.991 test1[1021:62291] A------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.992 test1[1021:62291] A------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.992 test1[1021:62291] A------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.992 test1[1021:62291] B------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] B------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] B------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] C------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] C------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.993 test1[1021:62291] C------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.994 test1[1021:62291] D------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.994 test1[1021:62291] D------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
2016-03-29 21:28:50.994 test1[1021:62291] D------<NSThread: 0x7fcaa2201900>{number = 2, name = (null)}
上面两句话结合代码分析:就是当我们把我们要做的事情(任务)添加进一个队列中,可能我们分多次添加,上面的代码中我是跟两次在queue队列中添加任务,当GCD把queue队列中的任务取出放到对应的线程中执行的时候, 它会遵守FIFO(先进先出的原则),先执行第一次添加的任务(输出A B),然后执行第二次添加的任务(输出C D),为什么输出结果中会首先输出E呢? 因为这里执行的异步函数执行任务,不会阻塞线程 (下面会讲异步函数) 串行队列 + 异步执行函数会开启一条子线程
注意:上面的案例是在MRC中,所以通过creat创建出来的队列,需要release!
/********************************创建串行queue队列********************************/dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
/********************************创建并发queue队列********************************/dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);
串行队列:队列中的任务执行的方式:任务一个接着一个的执行(一个执行完毕以后,在执行下一个任务)
并发队列:当GCD取出队列中的任务的时候,执行的方式:如果是异步执行的方式的执行下,自动开启多个线程同时执行任务)
将上面的案例中的队列更改成并发队列,我们分析下结果:
/********************************创建并发queue队列********************************/dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{/********************************第一次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"A------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"B------%@", [NSThread currentThread]);}});dispatch_async(queue, ^{/********************************第二次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"C------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"D------%@", [NSThread currentThread]);}});dispatch_release(queue);NSLog(@"E--------%@", [NSThread currentThread]);
输出结果:
2016-03-29 21:48:37.056 test1[1043:68365] E--------<NSThread: 0x7fd838402780>{number = 1, name = main} 2016-03-29 21:48:37.056 test1[1043:68403] C------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)} 2016-03-29 21:48:37.056 test1[1043:68404] A------<NSThread: 0x7fd83843b470>{number = 3, name = (null)} 2016-03-29 21:48:37.056 test1[1043:68404] A------<NSThread: 0x7fd83843b470>{number = 3, name = (null)} 2016-03-29 21:48:37.056 test1[1043:68403] C------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)} 2016-03-29 21:48:37.057 test1[1043:68404] A------<NSThread: 0x7fd83843b470>{number = 3, name = (null)} 2016-03-29 21:48:37.057 test1[1043:68403] C------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)} 2016-03-29 21:48:37.057 test1[1043:68404] B------<NSThread: 0x7fd83843b470>{number = 3, name = (null)} 2016-03-29 21:48:37.057 test1[1043:68403] D------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)} 2016-03-29 21:48:37.057 test1[1043:68404] B------<NSThread: 0x7fd83843b470>{number = 3, name = (null)} 2016-03-29 21:48:37.057 test1[1043:68403] D------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)} 2016-03-29 21:48:37.058 test1[1043:68404] B------<NSThread: 0x7fd83843b470>{number = 3, name = (null)} 2016-03-29 21:48:37.058 test1[1043:68403] D------<NSThread: 0x7fd838601ed0>{number = 2, name = (null)}
结果分析:第一行依然输出的是E;因为我们执行任务的方式是异步函数,所以不会堵塞线程,输出的是E,但是这次由于我们创建的队列是并发的,当GCD从队列中取出任务的时候,会自动创建多个线程(根据CPU资源创建),不仅从输出的结果可以看出,创建多条线程,并且执行的任务的时候没有顺序的,说明是并发执行任务的
下面我们看一下同步函数执行任务 + 串行队列 或者 并发队列是什么结果呢
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{/********************************创建异步queue队列********************************/dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);dispatch_sync(queue, ^{/********************************第一次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"A------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"B------%@", [NSThread currentThread]);}});/********************************同步方式执行********************************/dispatch_sync(queue, ^{/********************************第二次向queue添加任务********************************/for (int i = 0; i<3; i++) {NSLog(@"C------%@", [NSThread currentThread]);}for (int i = 0; i<3; i++) {NSLog(@"D------%@", [NSThread currentThread]);}});dispatch_release(queue);NSLog(@"E--------%@", [NSThread currentThread]);
}
输出结果
2016-03-29 22:04:22.972 test1[1122:74978] A------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.972 test1[1122:74978] A------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] A------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] B------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] B------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] B------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] C------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.973 test1[1122:74978] C------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] C------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] D------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] D------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] D------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
2016-03-29 22:04:22.974 test1[1122:74978] E--------<NSThread: 0x7f9f3a507f20>{number = 1, name = main}
输出的结果:当执行任务的方式采用的是同步执行的时候,不管是串行队列,还是并发队列,都不会开启子线程<也就是说,并发队列只在异步函数执行任务中会有效(创建子线程), E输出在最后输出,整体发现,任务是在主线程执行,并且任务是按着循序执行的,也就是说同步函数会阻塞线程!
全局队列
全局并发队列
GCD默认已经提供了全局的并发队列,供整个应用使用,可以无需手动创建
/*** <#Description#>** @param identifier#> 队列的优先级 一般也传0* @param flags#> 此参数暂时无用,用0即可* 全局并发队列的优先级#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台*/dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
全局主队列
dispatch_queue_t queue = dispatch_get_main_queue();
线程之间通信
从子线程回到主线程
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 执行耗时的异步操作...dispatch_async(dispatch_get_main_queue(), ^{// 回到主线程,执行UI刷新操作});
});
在开发中GCD的其他常用API接口
延时执行
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{[self performSelector:@selector(task) withObject:nil afterDelay:2.0]; }- (void)task {NSLog(@"延迟2秒执行---%@", [NSThread currentThread]); }
输出结果
2016-03-29 22:29:43.308 test1[1153:84643] 延迟2秒执行---<NSThread: 0x7fa682e005e0>{number = 1, name = main}
结果分析:延迟两秒执行task方法,在task所在的线程是主线程
一次性代码
使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{// 只执行1次的代码(这里面默认是线程安全的)
});
在整个程序中,只会执行一次,开发中可用于单例
单例模式
ARC中,单例模式的实现 在.m中保留一个全局的static的实例 static id _instance;重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全) + (instancetype)allocWithZone:(struct _NSZone *)zone {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_instance = [super allocWithZone:zone];});return _instance; }
提供1个类方法让外界访问唯一的实例 + (instancetype)sharedInstance {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{_instance = [[self alloc] init];});return _instance; }实现copyWithZone:方法 - (id)copyWithZone:(struct _NSZone *)zone {return _instance; }
快速迭代
// 使用dispatch_apply函数能进行快速迭代遍历NSArray *array = @[@"coder_hong", @"zhangsan", @"lishi"];NSUInteger count = array.count;dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t index){// 执行10次代码,index顺序不确定NSLog(@"%@", array[index]);});
输出结果:
2016-03-29 22:45:47.886 test1[1228:91621] coder_hong
2016-03-29 22:45:47.886 test1[1228:91661] lishi
2016-03-29 22:45:47.886 test1[1228:91657] zhangsan
转载于:https://www.cnblogs.com/mshong/p/5334890.html
多线程--GCD的基本用法相关推荐
- C#多线程中lock的用法
最近在看些c#的代码,发现很多是以前没有接触到了,只能上网查,把比较好的整理下来. 经常碰到同时需要对某个数据进行操作,或者对某个文件进行读写操作,对于这些操作我们以前往往不能很好的进行处理,自从C# ...
- iOS 多线程-GCD栅栏方法
iOS 多线程-GCD任务+队列. iOS 多线程-GCD队列组. iOS 多线程-GCD栅栏方法. 上一篇文章记录了队列组的使用,是为了处理多个任务之间的顺序.但是开发中会出现多组任务的顺序问题. ...
- 多线程中Condition的用法
多线程中Condition的用法与Object中wait.notify.notifyAll用法非常的相似 Condition与Lock对象搭配完成等待唤醒机制 首先我们需要创建Condition对象 ...
- swift 多线程GCD和延时调用
GCD 是一种非常方便的使用多线程的方式.通过使用 GCD,我们可以在确保尽量简单的语法的前提下进行灵活的多线程编程.在 "复杂必死" 的多线程编程中,保持简单就是避免错误的金科玉 ...
- iOS多线程GCD 研究
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法. dispatch queue分成以下三种: 1)运行在主线程的Main queue,通过dispat ...
- Swift - 多线程GCD详解
// GCD详解 // 目录: // 1. 创建GCD队列(最常用) // 2. 自定义创建队列 // 3. 使用多线程实现延迟加载 // 4. 使用多线程实现重复(循环) // 5. ...
- Java 多线程:synchronized 关键字用法(修饰类,方法,静态方法,代码块)
前言 在 多线程生成的原因(Java内存模型与i++操作解析) 中,介绍了Java的内存模型,从而可能导致的多线程问题.synchronized就是避免这个问题的解决方法之一.除了 synchroni ...
- IOS开发之多线程 -- GCD的方方面面
前言:这篇GCD的博文是本人阅读了很多海内外大神的关于GCD的文章,以及结合之前自己对GCD的粗浅的认识,然后取其精华,去其槽粕,综合起来的笔记,而且是尽可能的以通熟易懂的并且是正确的理论论述方式呈现 ...
- iOS 多线程GCD
为了了解.记忆更深刻,记录下,后面也会附上自己git 上demo,欢迎互相学习!! 一:什么是GCD GCD本身是苹果公司为多核的并行运算提出的解决方案.GCD在工作时会自动利用更多的处理器核心,以充 ...
最新文章
- Lock接口Condition,以及Lock与synchronized异同
- localdatetime 获取天_LocalDateTime的一些用法
- C++编译过程中没有找到MFC80UD.DLL,因此这个程序未能启动.重新安装应用程序可能会修复此问题? 的彻底解决...
- System76 是如何打造开源硬件的
- 2021 年百度之星·程序设计大赛 - 初赛三
- 【转载】SNMPv3 配置及snmpwalk命令信息获取
- jquery 移动端 ui 组件库 移动端前端UI库—Frozen UI、SUI Mobile、light7、WeUI、jqweui
- Linux(ubuntu18.04)安装eclipse教程
- macOS中显示按键操作
- 圣诞节苹果服务器没有人维护2020,2020圣诞节真的推迟到1月8号吗
- magedu第一天学习(计算机基础部分)
- 解读 2022 诺贝尔生理学或医学奖 | MedChemExpress
- mysql 主从1146_mysql 主从复制1146错误处理办法
- i3cpu驱动xp_Intel英特尔 Core i3/Core i5/Core i7系列CPU显示驱动 14.46.9.5394版 For XP-64
- 金属结构保温板的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
- html自动刷新 idea,idea新建css idea怎么刷新导入的css
- 连接数据库——模拟ATM机查、存、取、开户功能
- 代码大全(读书笔记)
- vue2对应的常用插件版本
- sqlite 表的列增加,修改,删除及表的重构和去重操作