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

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

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

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

提到多线程,也就是四种,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. Spring Setter Injection and Constructor Injection

    Setter Injection AppContext.xml <?xml version="1.0" encoding="UTF-8"?> < ...

  2. SURF算子(1)

    SURF算子,参考这篇文章的解释http://www.ipol.im/pub/art/2015/69/ SURF 是   Speeded Up Robust Features 加速鲁棒特征的含义. T ...

  3. JS魔法堂:mmDeferred源码剖析

    一.前言 avalon.js的影响力愈发强劲,而作为子模块之一的mmDeferred必然成为异步调用模式学习之旅的又一站呢!本文将记录我对mmDeferred的认识,若有纰漏请各位指正,谢谢.项目请见 ...

  4. Ionic2学习笔记(4):*号

    作者:Grey 原文地址: http://www.cnblogs.com/greyzeng/p/5544479.html                     大家常常会在ionic2页面中见到*号 ...

  5. 编写Chrome扩展程序

    Chrome的扩展程序很多,也很容易入门,可以来简单实现一下 看看,慢慢就能实现出一个扩展程序来 每个扩展程序应用一般会包含: 一个manifest清单文件 html文件 js文件 其他文件等 可以看 ...

  6. eclipse设置及快捷键

    快捷键 查看所有快捷键: Ctrl+Shift+L 调试代码: F11 逐语句: F5 逐过程: F6 快速执行代码: Ctrl+F11 自动格式化代码: Ctrl+Shift+F 在本行代码下插入新 ...

  7. 【FTP】C# System.Net.FtpClient库连接ftp服务器(上传文件)

    如果自己单枪匹马写一个连接ftp服务器代码那是相当恐怖的(socket通信),有一个评价较高的dll库可以供我们使用. 那就是System.Net.FtpClient,链接地址:https://net ...

  8. 关于js性能

    1,声明变量要赋初值2,尽量避免声明全局变量,可以减少与系统的重名3,当编写大量js代码时,难免会遇到命名冲突,这是可以通过模拟命名空间方式     来避免冲突4,尽量避免使用全局变量,搜索全局变量是 ...

  9. SignalR入门之从外部访问持久性连接或Hub

    有的时候,需要从外部访问持久性连接或Hub服务. 比如,假设A和B两个客户端正在聊天,那么系统或第三方在不参与聊天的情况需要为他们发送系统消息,那么此时,就需要独立来访问持久性连接或Hub服务. 之前 ...

  10. grep命令的使用

    grep是UNIX和LINUX中使用最广泛的命令之一.grep允许对文本文件进行模式查找.如果找到匹配模式, grep打印包含模式的所有行.grep支持基本正则表达式,也支持其扩展集.grep有三种变 ...