在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
iOS中处理多核并发的技术有两种分别是:`Grand Central Dispatch`(以下简称`GCD`)和`NSOperationQueue`框架。iOS开发的老司机们在程序开发中处理多个任务同时执行的时候,一定都会使用到这两个框架,而且GCD依靠它简洁的语法和对block的运用一直很受大家的青睐。ios开发中你一定明白 这样一条原则:“任何用于界面ui刷新和用户交互的操作都要放在主线程来操作,任何耗时或者耗CPU的任务必须在异步线程去操作*”,----小白都会问为什要这样,老司机都说记住就好-------这里就简单解释下: 首先我们来解释第一句话:“任何用于界面ui刷新和用户交互的操作都要放在主线程来操作”,要明白这句话只要明白下面几个点:1.主线程是线程安全的--把所有ui刷新以及用户的交互放在主线程操作会避免很多意外情况的发生,保证在获取服务端返回的数据时,ui界面可以及时安全的刷新数据,给用户带来良好体验 。2.ios中只有主线程才可以立刻刷新ui界面,如果放在异步线程去操作都会造成线程阻塞和延迟的问题。---第二点“任何耗时或者耗CPU的任务必须在异步线程去操作”---如果你很好的明白了前半句,那么这句话的意思就很好理解了,把耗时或者消耗cpu的操作放在异步线程,也就是为了防止线程的阻塞延迟,防止主线程上的ui刷新和用户操作的一系列动作出现卡顿,死锁,延迟等问题。 2.正文言归正传,我们继续往下看,如果你对ios的中的GCD和DispatchQueue 使用很熟练的话,那么swift3.0的语法和使用应该就是轻车熟路,如果你还不是特别明白GCD是什么鬼?没关系,这里先给大家来点山里的干货: 1. `dispatch queue`:一堆在主线程(或后台线程)上同步(或异步)来执行的代码,一旦被创建出来,操作系统就开始接手管理,在CPU上分配时间片来执行队列内的代码。开发者没法参与`queue`的管理。队列采用`FIFO模式`(先进先出),意味着先加入的也会被先完成,这和超市排队买单,队伍前的总是最先买单出去,的道理是一样一样的。 2. `work item`:一段代码块,可以在queue创建的时候添加,也可以单独创建方便之后复用,你可以把它当成将要在`queue`上运行的一个代码块。`work items`也遵循着`FIFO模式`,也可以同步(或异步)执行,如果选择同步的方式,运行中的程序直到代码块完成才会继续之后的工作,相对的,如果选择异步,运行中的程序在触发了代码块就立刻返回了。 3. `serial`(串行)vs`concurrent`(并行):`serial`将会执行完一个任务才会开始下一个,`concurrent`触发完一个就立即进入下一个,而不管它是否已完成。 接下来直奔主题:Swift3.0 中的GCD和DispatchQueue 使用。1.'serial'(串行) vs 'concurrent'(并行)1.1 创建一个DispatchQueue的方法:label:后面是一个标识,可以随便写,一般建议写成你的工程的dns的反序比较好。 1.2 接下来我们创建一个串行的queue 和 在主线程中执行的代码对比下看看串行队列和主线程的区别?然后我们在viewdidload中执行这个方法,看下控制台打印的结果: 从结果中我们可以看到两个方法是一个一个按顺序来执行的,也就是说串行队列和主线程一样都是串行输出的。换句话说也就是:主线程也是一个串行队列。 那异步(并行)队列执行会是怎么样呢? 看下输出结果: 这次我们惊喜地发现和上次不同,并且主线程的函数和异步队列的函数是交替执行 也就是说二者同步的输出,这是因为:异步队列不会阻塞当前线程 而是会另开一个线程来执行当前的任务,而主线程上的任务也就不会被阻塞,所以二者是同步输出的。 通过上面的对比我们至少可以明白两个件事:1. 使用async主线程和后台线程可以并行执行任务 2. 使用sync则只能串行执行任务, 当前线程被卡住直到串行任务完成才继续 2.GCD服务等级--Qos队列弄明白'serial'(串行) 和'concurrent'(并行)的关系,我们继续来看下GCD的qos队列。 GCD服务等级(GCD QoS):确定任务重要和优先级的属性 QoS是个基于具体场景的枚举类型,在初始队列时,可以提供合适的QoS参数来得到相应的权限,如果没有指定QoS,那么初始方法会使用队列提供的默认的QoS值 QoS等级(QoS classes),从前到后,优先级从高到低: userInteractive userInitiated default utility background unspecified 从上面的介绍 我们猜想 肯定是 ---等级越高的队列越先被执行,同一等级下的队列中 串行队列肯定是一个一个执行,异步队列肯定是分线程并行执行---下面我们就来验证下: 2.1 首先创建一个Qos队列:qos:需要传一个DispatchQoS的枚举类型 2.2 同个队列同等级串行输出对比看下输出结果: 仔细观察 我们会发现 结果并没有像我们猜想的那样 同等级下的异步队列 并行输出,这是怎么回事呢?因为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接收的是一个数组,所以聪明的你肯定知道怎么办吧???? 3.延迟执行当你的应用的某个流程中的某项任务延迟执行,GCD允许你执行某个方法来达到特定时间后运行你指定任务的目的。直接上代码: 这里解释下:.now() 方法 是获取当前时间。 4.DispatchWorkItemDispatchWorkItem是一个代码块,它可以被分到任何的队列,包含的代码可以在后台或主线程中被执行,简单来说:它被用于替换我们前面写的代码block来调用。使用起来也很简单,看代码: 5.主线程更新UI最后给大家分享一个开篇说到的主线程刷新ui的例子,先看代码: 使用的时候 记得在viewDidLoad 中调用setingIMage() 这个方法。 这里主要想和大家介绍下swift中的懒加载和oc中的异同,个人总结了下大家可以参阅:
|
请发表评论