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.组合
随机推荐
- Android自动化测试之Monkeyrunner学习笔记(一)
Android自动化测试之Monkeyrunner学习笔记(一) 因项目需要,开始研究Android自动化测试方法,对其中的一些工具.方法和框架做了一些简单的整理,其中包括Monkey.Monkeyr ...
- storm坑之---传递对象
继之前遇到的那个同步问题的坑之后(storm坑之---同步问题),最近对代码又做了调整和重构,并且又遇到了另一个storm开发中应该值得警惕的坑.接下来说说这个坑的大体情况. 在我的storm程序中, ...
- SQL Server时间粒度系列----第4节季、年时间粒度详解
本文目录列表: 1.SQL Server季时间粒度2.SQL Server年时间粒度 3.总结语 4.参考清单列表 SQL Serve季时间粒度 季时间粒度也即是季度时间粒度.一年每3 ...
- [译]学习IPython进行交互式计算和数据可视化(二)
第一章:开始使用IPython 在本章中,我们首先进行一遍IPython的安装过程,在大概浏览一下IPython提供的功能.IPython提供了一个高度优化的Python控制台和Notebook.除此 ...
- 将RichTextBox的内容直接写入数据库:
将RichTextBox的内容直接写入数据库: private void button1_Click(object sender, EventArgs e) { System.IO.Memory ...
- 炉石传说 C# 开发笔记(BS上线尝试)
昨天买了一个月的1G 1核的服务器,由于不是新用户,所以没有享受到阿里的6个月免费的优惠. (阿里脑残,为什么不对于续费或者升级免费呢?) 在服务器的通讯上面已经OK了,完全绕过了ASP.NET,就是 ...
- Extjs 回车查询
listeners: { afterRender: function (thisForm, options) { this.keyNav = Ext.create('Ext.util.KeyNav', ...
- 速战速决 (1) - PHP: 概述, 常量, 变量, 运算符, 表达式, 控制语句
[源码下载] 速战速决 (1) - PHP: 概述, 常量, 变量, 运算符, 表达式, 控制语句 作者:webabcd 介绍速战速决 之 PHP 概述 常量 变量 运算符 表达式 控制语句 示例1. ...
- Scalaz(54)- scalaz-stream: 函数式多线程编程模式-Free Streaming Programming Model
长久以来,函数式编程模式都被认为是一种学术研究用或教学实验用的编程模式.直到近几年由于大数据和多核CPU的兴起造成了函数式编程模式在一些实际大型应用中的出现,这才逐渐改变了人们对函数式编程无用论的观点 ...
- Scalaz(0) - 写在前面
面向对象编程范畴(OOP)从80年代C++到90年代java的兴起已经经历了几十年的高潮,是不是已经发展到了尽头,该是函数式编程(FP)开始兴旺发达的时候了吧.这样说似乎心眼儿有点坏,可能会得罪当今大 ...