iOS多线程中,队列和执行的排列组合结果分析
本文是对以往学习的多线程中知识点的一个整理。
多线程中的队列有:串行队列,并发队列,全局队列,主队列。
执行的方法有:同步执行和异步执行。那么两两一组合会有哪些注意事项呢?
如果不是在董铂然博客园看到这边文章请 点击查看原文
提到多线程,也就是四种,pthread,NSthread,GCD,NSOperation
其中phtread是跨平台的。GCD和NSOperation都是常用的,后者是基于前者的。
但是两者区别:GCD的核心概念是将一个任务添加到队列,指定任务执行的方法,然后执行。 NSOperation则是直接将一个操作添加到队列中。
为了整体结构更加清晰,我是用GCD来做此排列组合的实验。实验主要是通过循环内打印和主线程的打印先后顺序来判断结果,最后再加以总结
1.串行队列,同步执行
dispatch_queue_t q = dispatch_queue_create("dantesx", NULL); // 执行任务
for (int i = 0; i<10; i++) {
dispatch_sync(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
} NSLog(@"董铂然 come here");
运行效果:
执行结果可以清楚的看到全在主线程执行,并且是按照数序执行,循环结束之后主线程的打印才输出。
2.串行队列,异步执行
dispatch_queue_t q = dispatch_queue_create("dantesx", NULL); for (int i = 0; i<10; i++) {
dispatch_async(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
// [NSThread sleepForTimeInterval:0.001];
NSLog(@"董铂然 come here");
运行结果
结果显示,系统开了1条异步线程,因此全部在线程2执行,并且是顺序执行。主线程打印虽然在最上面,但是这个先后顺序是不确定,如果睡个0.001秒,主线程的打印会混在中间。
3.并发队列,异步执行
// 1. 队列
dispatch_queue_t q = dispatch_queue_create("dantesx", DISPATCH_QUEUE_CONCURRENT); // 2. 异步执行
for (int i = 0; i<10; i++) {
dispatch_async(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
// [NSThread sleepForTimeInterval:2.0];
NSLog(@"董铂然 come here");
运行结果
结果显示,主线程的打印还是混在中间不确定的,因为异步线程就是谁也不等谁。系统开了多条线程,并且执行的顺序也是乱序的
4.并发队列,同步执行
// 1. 队列
dispatch_queue_t q = dispatch_queue_create("dantesx", DISPATCH_QUEUE_CONCURRENT); // 2. 同步执行
for (int i = 0; i<10; i++) {
dispatch_sync(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
// [NSThread sleepForTimeInterval:2.0];
NSLog(@"董铂然 come here");
运行结果
这个运行结果和第1种的串行队列,同步执行是一模一样的。 因为同步任务的概念就是按顺序执行,后面都要等。言外之意就是不允许多开线程。 同步和异步则是决定开一条还是开多条。
所以一旦是同步执行,前面什么队列已经没区别了。
5.主队列,异步执行
// 1. 主队列 - 程序启动之后已经存在主线程,主队列同样存在
dispatch_queue_t q = dispatch_get_main_queue();
// 2. 安排一个任务
for (int i = 0; i<10; i++) {
dispatch_async(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
NSLog(@"睡会");
[NSThread sleepForTimeInterval:2.0];
NSLog(@"董铂然 come here");
运行结果
结果显示有点出人意料。主线程在睡会之后才打印,循环一直在等着。因为主队列的任务虽然会加到主线程中执行,但是如果主线程里也有任务就必须等主线程任务执行完才轮到主队列的。
6.主队列,同步执行
dispatch_queue_t q = dispatch_get_main_queue(); NSLog(@"卡死了吗?"); dispatch_sync(q, ^{
NSLog(@"我来了");
}); NSLog(@"董铂然 come here");
运行结果为卡死
卡死的原因是循环等待,主队列的东西要等主线程执行完,而因为是同步执行不能开线程,所以下面的任务要等上面的任务执行完,所以卡死。这是排列组合中唯一一个会卡死的组合。
7.同步任务的使用场景
dispatch_queue_t q = dispatch_queue_create("dantesx", DISPATCH_QUEUE_CONCURRENT);
// 1. 用户登录,必须要第一个执行
dispatch_sync(q, ^{
[NSThread sleepForTimeInterval:2.0];
NSLog(@"用户登录 %@", [NSThread currentThread]);
});
// 2. 扣费
dispatch_async(q, ^{
NSLog(@"扣费 %@", [NSThread currentThread]);
});
// 3. 下载
dispatch_async(q, ^{
NSLog(@"下载 %@", [NSThread currentThread]);
});
NSLog(@"董铂然 come here");
运行结果
结果显示,“用户登陆”在主线程打印,后两个在异步线程打印。上面的“用户登陆”使用同步执行,后面的扣费和下载都是异步执行。所以“用户登陆”必须第一个打印出来不管等多久,然后后面的两个异步和主线程打印会不确定顺序的打印。这就是日常开发中,那些后面对其有依赖的必须要先执行的任务使用同步执行,然后反正都要执行先后顺序无所谓的使用异步执行。
8.block异步任务包裹同步任务
dispatch_queue_t q = dispatch_queue_create("dantesx", DISPATCH_QUEUE_CONCURRENT);
void (^task)() = ^ {
// 1. 用户登录,必须要第一个执行
dispatch_sync(q, ^{
NSLog(@"用户登录 %@", [NSThread currentThread]);
});
// 2. 扣费
dispatch_async(q, ^{
NSLog(@"扣费 %@", [NSThread currentThread]);
});
// 3. 下载
dispatch_async(q, ^{ NSLog(@"下载 %@", [NSThread currentThread]);
});
}; dispatch_async(q, task);
[NSThread sleepForTimeInterval:1.0];
NSLog(@"董铂然 come here");
运行结果
因为整个block是在异步执行的,所以即使里面“用户登陆”是同步执行,那也无法在主线程中执行,只能开一条异步线程执行,因为是同步的所以必须等他先执行,后面的“扣费”和“下载”在上面同步执行结束之后,不确定顺序的打印。
9.全局队列
dispatch_queue_t q = dispatch_get_global_queue(0, 0); for (int i = 0; i < 10; i++) {
dispatch_async(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
[NSThread sleepForTimeInterval:1.0];
NSLog(@"com here");
运行结果
全局队列的本质就是并发队列,只是在后面加入了,“服务质量”,和“调度优先级” 两个参数,这两个参数一般为了系统间的适配,最好直接填0和0。
如果不是在董铂然博客园看到这边文章请 点击查看原文
总结:
1. 开不开线程,取决于执行任务的函数,同步不开,异步开。
2. 开几条线程,取决于队列,串行开一条,并发开多条(异步)
3. 主队列: 专门用来在主线程上调度任务的"队列",主队列不能在其他线程中调度任务!
4. 如果主线程上当前正在有执行的任务,主队列暂时不会调度任务的执行!主队列同步任务,会造成死锁。原因是循环等待
5. 同步任务可以队列调度多个异步任务前,指定一个同步任务,让所有的异步任务,等待同步任务执行完成,这是依赖关系。
6. 全局队列:并发,能够调度多个线程,执行效率高,但是相对费电。 串行队列效率较低,省电省流量,或者是任务之间需要依赖也可以使用串行队列。
7. 也可以通过判断当前用户的网络环境来决定开的线程数。WIFI下6条,3G/4G下2~3条。
iOS多线程中,队列和执行的排列组合结果分析的更多相关文章
- iOS多线程中的单例
#import "MyHandle.h" static MyHandle *handle = nil; @implementation MyHandle // 传统写法 // 此时 ...
- iOS多线程中performSelector: 和dispatch_time的不同
iOS中timer相关的延时调用,常见的有NSObject中的performSelector:withObject:afterDelay:这个方法在调用的时候会设置当前runloop中timer,还有 ...
- iOS多线程中performSelector
下面两段代码都在主线程中运行,我们在看别人代码时会发现有时会直接调用,有时会利用performSelector调用,今天看到有人在问这个问题,我便做一下总结, [delegate imageDownl ...
- 浅谈iOS开发中方法延迟执行的几种方式
Method1. performSelector方法 Method2. NSTimer定时器 Method3. NSThread线程的sleep Method4. GCD 公用延迟执行方法 - (vo ...
- iOS开发中方法延迟执行的几种方式
概述 项目开发中经常会用到方法的延时调用,下面列举常用的几种实现方式: 1.performSelector 2.NSTimer 3.NSThread线程的sleep 4.GCD 1.performSe ...
- iOS 多线程(队列、任务、串行、并行、同步、异步)
- c语言中一种典型的排列组合算法
c语言中的全排列算法和组合数算法在实际问题中应用非常之广,但算法有许许多多,而我个人认为方法不必记太多,最好只记熟一种即可,一招鲜亦可吃遍天 全排列: #include<stdio.h> ...
- iOS 多线程:『GCD』详尽总结
本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法.这大概是史上最详细.清晰的关于 GCD 的详细讲解+总结的文章了.通过本文,您将了解到: 1. GCD 简介 2. GCD 任务和队列 ...
- 2018.11.20-day22 类中代码的执行顺序&组合
1.类中代码的执行顺序 2.组合
随机推荐
- 【Java基础】创建和销毁对象
Num1:考虑用静态工厂方法代替构造器 对于类而言,常见的方法是提供一个公有的构造器,但其实还有一种方法叫做静态工厂方法(static factory method),它只是一个返回类的实例静态方法. ...
- 编译Linux内核
下面的实验以 debian7.5 64bit 为例. 获取源码 获取 debian7.5 本身的源码非常简单: sudo apt-get install linux-source https://ww ...
- Elasticsearch入门必备——ES中的字段类型以及常用属性
使用Elasticsearch时,了解字段的概念,是必不可少的.毕竟无论是es还是传统的数据库,都无法弱化字段的类型. 背景知识 在Es中,字段的类型很关键: 在索引的时候,如果字段第一次出现,会自动 ...
- requests模块--python发送http请求
requests模块 在Python内置模块(urllib.urllib2.httplib)的基础上进行了高度的封装,从而使得Pythoner更好的进行http请求,使用Requests可以轻而易举的 ...
- [AngularJS] AngularJS系列(2) 中级篇之路由
目录 原理 angular-route ui-router 事件 深度路由 原理 ng的route本质是监听hashchange事件. 在angular-route中 $rootScope.$on(' ...
- Android流量控制——列表页面
1.最简单的模式: 设计: 1.将页码值传给服务器,让服务器返回对应的页码数据 2.数据缓存:只缓存第一页数据. 好处: 1.实现简单.无脑 坏处: 1.浪费流量,如果用户一直在等某个人发送消息的话. ...
- 【转】万网域名查询接口(API)的说明
1.域名查询接口采用HTTP,POST,GET协议:调用URL:http://panda.www.net.cn/cgi-bin/check.cgi参数名称:area_domain 值为标准域名,例:h ...
- jQuery uploadify在谷歌和火狐浏览器下无法上传
原因: 由于jQuery uploadify是借助flash来实现上传的,每一次向后台发送数据流请求时,ie会自动把本地cookie存储捆绑在一起发送给服务器.但firefox.chrome不会这样做 ...
- C#多种方式获取文件路径
string str5=Application.StartupPath;//获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称. string str1 =Process.GetCurren ...
- 使用VS Code开发ASP.NET Core 应用程序
最新教程:http://www.cnblogs.com/linezero/p/VSCodeASPNETCore.html 使用VS Code开发ASP.NET Core 应用程序 准备 1.安装VS ...