本文是对以往学习的多线程中知识点的一个整理。

多线程中的队列有:串行队列,并发队列,全局队列,主队列

执行的方法有:同步执行和异步执行。那么两两一组合会有哪些注意事项呢?

如果不是在董铂然博客园看到这边文章请 点击查看原文

提到多线程,也就是四种,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多线程中,队列和执行的排列组合结果分析的更多相关文章

  1. iOS多线程中的单例

    #import "MyHandle.h" static MyHandle *handle = nil; @implementation MyHandle // 传统写法 // 此时 ...

  2. iOS多线程中performSelector: 和dispatch_time的不同

    iOS中timer相关的延时调用,常见的有NSObject中的performSelector:withObject:afterDelay:这个方法在调用的时候会设置当前runloop中timer,还有 ...

  3. iOS多线程中performSelector

    下面两段代码都在主线程中运行,我们在看别人代码时会发现有时会直接调用,有时会利用performSelector调用,今天看到有人在问这个问题,我便做一下总结, [delegate imageDownl ...

  4. 浅谈iOS开发中方法延迟执行的几种方式

    Method1. performSelector方法 Method2. NSTimer定时器 Method3. NSThread线程的sleep Method4. GCD 公用延迟执行方法 - (vo ...

  5. iOS开发中方法延迟执行的几种方式

    概述 项目开发中经常会用到方法的延时调用,下面列举常用的几种实现方式: 1.performSelector 2.NSTimer 3.NSThread线程的sleep 4.GCD 1.performSe ...

  6. iOS 多线程(队列、任务、串行、并行、同步、异步)

  7. c语言中一种典型的排列组合算法

    c语言中的全排列算法和组合数算法在实际问题中应用非常之广,但算法有许许多多,而我个人认为方法不必记太多,最好只记熟一种即可,一招鲜亦可吃遍天 全排列: #include<stdio.h> ...

  8. iOS 多线程:『GCD』详尽总结

    本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法.这大概是史上最详细.清晰的关于 GCD 的详细讲解+总结的文章了.通过本文,您将了解到: 1. GCD 简介 2. GCD 任务和队列 ...

  9. 2018.11.20-day22 类中代码的执行顺序&组合

    1.类中代码的执行顺序 2.组合

随机推荐

  1. 设计宝库:22套精美的 PhotoShop 素材免费下载

    <设计宝库>系列给大家带来22套精美的 PSD 设计素材,你可以免费下载使用.设计师经常会去网上搜罗各种各样的素材,这些免费素材不仅能帮助他们节省大量的时间,而且能有很好的效果.非常感谢那 ...

  2. JAVA 设计模式 外观模式

    用途 外观模式 (Facade) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式是一种结构型模式. 结构

  3. 使用Microsoft Fakes进行单元测试(1)

    一:什么是单元测试 单元测试是对软件进行准确性验证的步骤.单元测试并不进行整个软件功能的测试,仅仅是对于最小工作单元的测试.一般最小工作单元就是指方法/函数等. 这里并不打算对单元测试的概念及基础进行 ...

  4. C#协变和逆变

    我们知道在C#中,是可以将派生类的实例赋值给基类对象的.

  5. 插入排序---直接插入排序算法(Javascript版)

    将n个元素的数列分为已有序和无序两个部分. 数列:{a1,a2,a3,a4,…,an} 将该数列的第一元素视为有序数列,后面都视为无序数列: {{a1},{a2,a3,a4,…,an}} 将无序数列中 ...

  6. 获取MS SQL TABLE列名列表

    在MS SQL Server中,想获取表的所有列名,可以使用下面SQL语句: SELECT [COLUMN_NAME] FROM [INFORMATION_SCHEMA].[Columns] WHER ...

  7. 在吉日嘎拉DotNet.WebForm中使用FluentScheduler调度任务

    有些用户一直说系统发送的邮件一直收不到,投诉系统不正常,这时候怎么洗刷冤屈呢?将发送的每一封Email都保存到数据库中,并记录发送的日志,让用户无话可说. 自己创建3个表: MessageFailed ...

  8. 【Java每日一题】20161014

    20161013问题解析请点击今日问题下方的"[Java每日一题]20161014"查看 package Oct2016; import java.util.Arrays; imp ...

  9. PHP程序员7小时学会Kotlin 第二小时

    Kotlin中,一切皆对象:PHP则并非一切皆对象,甚至不需要对象的存在即可完成系统功能开发,我们现在可以接触到的旧的系统都可以说明这一点. 基本数据类型 数值型 类型 位长 双精度浮点型Double ...

  10. JAVA实现的微信扫描二维码支付

    吐槽一下 支付项目采用springMvc+Dubbo架构实现,只对外提供接口. 话说,为什么微信支付比支付宝来的晚了那么一点,一句话,那一阵挺忙的,然后就没有时间整理,最近做完支付宝支付,顺便也把微信 ...