利用GCD构建反应快,效率高的App WWDC

·  阅读 298

本文文章来自WWDC, 学习笔记,纯属备忘 利用GCD构建反应快,效率高的App WWDC developer.apple.com/wwdc15/718

什么是GCD

GCD是苹果开发的多线程编程,通过简单的API就可以创建新线程去执行我们需要的任务。

GCD类型

GCD有两种

非同步(asynchronous)具备开启新执行绪的能力,也具备跳过当前函数继续往下执行的能力。

同步(synchronous)不具备开启新执行绪的能力,也不具备跳过当前函数继续往下执行的能力。

GCD的优点

GCD是苹果多核的并行运算提出的解决方案 GCD会自动利用更多的的CPU内核(比如双核、四核) GCD会自动管理线程的生命周期 工程师只需要只要跟GCD说要执行什么程式,不需要写任何管理的程式码

GCD的队列 queue

Main Queue

Main Queue有最高优先级,并且在主线程上运行。所有UI更新都该在主线程上完成,如果没有,在应用程式上会导致crashes。

Global Queue

根据QOS(Quality of Service),此执行绪分为4种主要类型和一种默认类型,从最高顺位到最低顺位

1. userInteractive - 類似於主線程,工作是瞬時的
2. userInitiated - 運作時間只有幾秒鐘或更短
3. default- 系統會自行推斷出預設類型
4. utility - 運作需要幾秒到幾分
5. background - 運作需要大量時間,幾分鐘到幾小時
复制代码

Custom Queue

自定义序列是可以自行创建并提供所需的任何QOS的顺序

验证异步下不同队列的优先级
        DispatchQueue.global(qos: .userInitiated).async {
            for i in 0...5 {
                print("userInitiated,\(i)")
            }
        }
        DispatchQueue.global(qos: .userInteractive).async {
            for i in 0...5 {
                print("userInteractive-----,\(i)")
            }
        }

//print
userInteractive-----,0
userInitiated,0
userInteractive-----,1
userInitiated,1
userInteractive-----,2
userInitiated,2
userInteractive-----,3
userInitiated,3
userInteractive-----,4
userInteractive-----,5
userInitiated,4
userInitiated,5
复制代码

由于userInteractive 优先级比userInitiated要更高,所以,打印的时候userInteractive要更快一点.

验证同步下不同队列的优先级
 DispatchQueue.global(qos: .userInteractive).sync {
            for i in 0...5 {
                print("userInteractive-----,\(i)")
            }
        }
 DispatchQueue.global(qos: .userInitiated).sync {
        for i in 0...5 {
             print("userInitiated,\(i)")
        }
  }
  
print
userInteractive-----,0
userInteractive-----,1
userInteractive-----,2
userInteractive-----,3
userInteractive-----,4
userInteractive-----,5
userInitiated,0
userInitiated,1
userInitiated,2
userInitiated,3
userInitiated,4
userInitiated,5
复制代码

可以看到,GCD在同步队列下是userInteractive优先于userInitiated执行的,要把所有的userInteractive执行完,才会进行下一步.

理解iOS runloop与GCD的一些联系

Main Thread runloop

这张图里面 最左边是MainThread 里面runloop的处理事件,响应事件的流程,主线程runloop接收事件,处理Events,再通过各个响应链,传送到对应的位置处理

GCD处理后台事件

通过 GCD 提供的方法来将一些需要耗时操作放到非主线程上做,使得 App 能够运行的更加流畅响应更快。注意⚠️ 使用 GCD 时需要注意避免可能引起线程爆炸和死锁的情况,还有非主线程处理任务也不是万能的,如果一个处理需要消耗大量内存或者大量CPU操作 GCD 也没法帮你,只能通过将处理进行拆解分步骤分时间进行处理才比较妥当。

Main Thread runloop 接收处理结果

当GCD 完成事件后,会把结果返回主线程,进行反馈,这样主线程快速进行交互, 这是最典型的异步处理事件的方法

耗时长的任务

将 GCD 的 block 通过 dispatch_block_create_with_qos_class 方法指定队列的 QoS 为 QOS_CLASS_UTILITY(图中的UI)。这种 QoS 系统会针对大的计算,I/O,网络以及复杂数据处理做电量优化。

使用串行队列,同步操作来完成一个类似锁的操作

可以使用同步 因为有其他的线程或队列 也在访问此数据结构 或许当执行一个QoS线程时 在队列内调用”同步调用”函数 从而可以独占访问 数据结构 如果随后返回线程 同样的事情将出现 他将停止等待线程以获取独占访问权限 然后在调用QoS的线程中 执行自身QoS线程中的块

但是这个可能会出现 一个高级的优先级服务线程正在等待 较低级别的进程工作 我们可以通过为等待期间 提高等待工作的QoS来解决 如果你用串行队列和同步调用 或调用程序块等待API 如果你用多线程互斥锁 或任何建立在其上的API 如NSLock也可实现

GCD 如何使用临时线程完成任务

假如现在线程池有两个设备, 此时如图有两个任务,GCD无法把两个线程分配给三个代码任务, 1.先讲线程分配给前两个 2.当第一个执行完之后, 3.讲线程分配给第三个程序代码执行.

关于GCD线程等待

这样运作非常好 直到我们程序中的某个需要访问 现在还不可获得的资源. 我们把这叫做等待 线程将等待并暂缓执行 当它需要像是I/O或锁定资源时

关于线程激增

想象一下我们有四个这样的程序块 正在两个不同的线程上执行前两个 前一个说:嘿 我需要执行I/O 我们说:好我们将发布I/O到磁盘上 但之后我们必须等待I/O回归返回 然后才可提出另一个线程 执行下一个程序块等等 当线程等待时 当仍有工作需要被做时 找另一线程来执行队列上的下一程序块

这里的问题是: 如果仅有四个程序块时运行没有问题 如果我有许多程序块且它们都想等待 我们就会遇到线程激增

如果它们同时停止等待 就会有大量的资源冲突 所以这对性能来说是非常不好的

同时它也有一点危险性 因为这对可提出的程序数量有所限制 当我们耗尽极限时对于新的工作 我们该怎么办? 这就导致了死锁

主线程死锁

当主线程串行队列,开始同步的时候,就会导致卡死 主线程决定同步调度 成相同的串行队列 问题是对于串行队列 没有可用的线程,主调用将永远阻塞 这就是经典的死锁情况

认识一下常见的线程

Manger thread

几乎在所有使用GCD的应用程序中 都可以看到管理线程 它负责帮助进程调度来源 你会注意到调度管理线程是根框架

Idle GCD thread

(workq_kernreturn) 线程池里空闲的线程 在堆栈的底部 你可以看到开始工作队列线程 有迹象指出它是一个GCD线程 工作队列当前返回指出它正在处在空闲

Active GCD thread

Idle mian thread

分类:
iOS
标签:
分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改