iOS中处理多核并发的技术有两种分别是:`Grand Central Dispatch`(如下简称`GCD`)和`NSOperationQueue`框架。iOS开发的老司机们在程序开发中处理多个任务同时执行的时候,必定都会使用到这两个框架,并且GCD依靠它简洁的语法和对block的运用一直很受你们的青睐。ios开发中你必定明白 这样一条原则:“任何用于界面ui刷新和用户交互的操做都要放在主线程来操做,任何耗时或者耗CPU的任务必须在异步线程去操做*”,----小白都会问为什要这样,老司机都说记住就好-------这里就简单解释下: ios
首先咱们来解释第一句话:“任何用于界面ui刷新和用户交互的操做都要放在主线程来操做”,要明白这句话只要明白下面几个点:1.主线程是线程安全的--把全部ui刷新以及用户的交互放在主线程操做会避免不少意外状况的发生,保证在获取服务端返回的数据时,ui界面能够及时安全的刷新数据,给用户带来良好体验 。2.ios中只有主线程才能够马上刷新ui界面,若是放在异步线程去操做都会形成线程阻塞和延迟的问题。---第二点“任何耗时或者耗CPU的任务必须在异步线程去操做”---若是你很好的明白了前半句,那么这句话的意思就很好理解了,把耗时或者消耗cpu的操做放在异步线程,也就是为了防止线程的阻塞延迟,防止主线程上的ui刷新和用户操做的一系列动做出现卡顿,死锁,延迟等问题。swift
言归正传,咱们继续往下看,若是你对ios的中的GCD和DispatchQueue 使用很熟练的话,那么swift3.0的语法和使用应该就是轻车熟路,若是你还不是特别明白GCD是什么鬼?不要紧,这里先给你们来点山里的干货:api
1. `dispatch queue`:一堆在主线程(或后台线程)上同步(或异步)来执行的代码,一旦被建立出来,操做系统就开始接手管理,在CPU上分配时间片来执行队列内的代码。开发者无法参与`queue`的管理。队列采用`FIFO模式`(先进先出),意味着先加入的也会被先完成,这和超市排队买单,队伍前的老是最早买单出去,的道理是同样同样的。数组
2. `work item`:一段代码块,能够在queue建立的时候添加,也能够单首创建方便以后复用,你能够把它当成将要在`queue`上运行的一个代码块。`work items`也遵循着`FIFO模式`,也能够同步(或异步)执行,若是选择同步的方式,运行中的程序直到代码块完成才会继续以后的工做,相对的,若是选择异步,运行中的程序在触发了代码块就马上返回了。安全
3. `serial`(串行)vs`concurrent`(并行):`serial`将会执行完一个任务才会开始下一个,`concurrent`触发完一个就当即进入下一个,而无论它是否已完成。并发
label:后面是一个标识,能够随便写,通常建议写成你的工程的dns的反序比较好。框架
而后咱们在viewdidload中执行这个方法,看下控制台打印的结果:异步
从结果中咱们能够看到两个方法是一个一个按顺序来执行的,也就是说串行队列和主线程同样都是串行输出的。换句话说也就是:主线程也是一个串行队列。async
那异步(并行)队列执行会是怎么样呢?函数
看下输出结果:
此次咱们惊喜地发现和上次不一样,而且主线程的函数和异步队列的函数是交替执行 也就是说两者同步的输出,这是由于:异步队列不会阻塞当前线程 而是会另开一个线程来执行当前的任务,而主线程上的任务也就不会被阻塞,因此两者是同步输出的。
1. 使用async主线程和后台线程能够并行执行任务
2. 使用sync则只能串行执行任务, 当前线程被卡住直到串行任务完成才继续
弄明白'serial'(串行) 和'concurrent'(并行)的关系,咱们继续来看下GCD的qos队列。
GCD服务等级(GCD QoS):肯定任务重要和优先级的属性
QoS是个基于具体场景的枚举类型,在初始队列时,能够提供合适的QoS参数来获得相应的权限,若是没有指定QoS,那么初始方法会使用队列提供的默认的QoS值
QoS等级(QoS classes),从前到后,优先级从高到低:
userInteractive
userInitiated
default
utility
background
unspecified
从上面的介绍 咱们猜测 确定是 ---等级越高的队列越先被执行,同一等级下的队列中 串行队列确定是一个一个执行,异步队列确定是分线程并行执行---下面咱们就来验证下:
qos:须要传一个DispatchQoS的枚举类型
看下输出结果:
仔细观察 咱们会发现 结果并无像咱们猜测的那样 同等级下的异步队列 并行输出,这是怎么回事呢?由于Qos队列默认是串行执行的,因此即便qos队列中的方法是异步的 也会被顺序串行执行。那么怎样才能够并行执行呢?这就要用到Qos队列的另一个属性:attributes:.concurrent
具体写法:
看下具体函数和运行结果:
经过输出结果咱们发现 结果是并行输出了,可是细心的你是否是发现告终果中的一丝丝不一样,附上的两张结果图,是同一个函数运行屡次显示的不一样结果,为何会不一样呢?难道程序有问题,一个函数怎么可能有两个结果呢?是否是顿时一脸懵逼,一万个草泥马在心中奔腾😢😢😢😢😢😢😢😢😢😢😢😢😢😢😢😢----施主息怒,待山里娃慢慢给你分析:
首先咱们要明白系统所谓的并行执行,并不全是咱们想象那的样是固定的像log1中的同样十分规矩的输出,内部是会发生资源的倾斜或者顺序的不肯定性的,继续看下去后面的例子你定会完全明白。
咱们新建一个不一样等级的Qos队列来看下结果:
输出结果:
观察结果 ,咱们会发现并非咱们以前猜想的 等级越高的队列会快速先执行完,而是高等级和低等级的交叉进行输出,仔细想下 其实这就是上面那个问题的完美诠释,系统会使优先级更高的`queue1`比`queue2`更快被执行,虽然在`queue1`运行的时候`queue2`获得一个运行的机会,系统仍是将资源倾斜给了被标记为更重要的`queue1`,等`queue1`内的任务所有被执行完成,系统才开始全心全意服务于`queue2` 。---看到这里应该明白了吧。
你们能够在思考个问题,在这些等级中 main queue主线程队列是排在哪一个等级呢?下面咱们来看个例子:
结果:
从中咱们能够清楚的得出结论:`main queue`默认就有一个很高的权限。
接下来咱们在来看下Qos队列attributes的另一个属性,initiallyInactive (不活跃的),咱们能够建立一个qos的不活跃队列,这个队列的特色是 须要调用DispatchQueue类的`activate()`让任务执行。看下具体代码:
重点在下面,viewdidload中调用:
看下输出结果:
咱们发现队列是串行输出的,那么怎样建立一个并行的initiallyInactive 队列呢?查看api咱们会发现Qos队列的attributes接收的是一个数组,因此聪明的你确定知道怎么办吧😊
当你的应用的某个流程中的某项任务延迟执行,GCD容许你执行某个方法来达到特定时间后运行你指定任务的目的。直接上代码:
这里解释下:.now() 方法 是获取当前时间。
DispatchWorkItem是一个代码块,它能够被分到任何的队列,包含的代码能够在后台或主线程中被执行,简单来讲:它被用于替换咱们前面写的代码block来调用。使用起来也很简单,看代码:
最后给你们分享一个开篇说到的主线程刷新ui的例子,先看代码:
使用的时候 记得在viewDidLoad 中调用setingIMage() 这个方法。
这里主要想和你们介绍下swift中的懒加载和oc中的异同,我的总结了下你们能够参阅:
连接:http://www.jianshu.com/p/737233208d40