Objective-C高级编程读书笔记之GCD

464 查看

Objective-C高级编程
iOS与OS X多线程和内存管理

Grand Central Dispatch (GCD)

目录

  1. 什么是GCD
  2. 什么是多线程, 并发
  3. GCD的优势
  4. GCD的API介绍
  5. GCD的注意点
  6. GCD的使用场景
  7. Dispatch Source
  8. 总结

1. 什么是GCD

GCD, Grand Central Dispatch, 可译为”强大的中枢调度器”, 基于libdispatch, 纯C语言, 里面包含了许多多线程相关非常强大的函数. 程序员可以既不写一句线程管理的代码又能很好地使用多线程执行任务.

GCD中有Dispatch QueueDispatch Source. Dispatch Queue是主要的, 而Dispatch Source比较次要. 所以这里主要介绍Dispatch Queue, 而Dispatch Source在下面会简单介绍.

Dispatch Queue

苹果官方对GCD的说明如下 :

开发者要做的只是定义想执行的任务并追加到适当的Dispatch Queue中.

这句话用源代码表示如下

该源码用block的语法定义想执行的任务然后通过dispatch_async函数讲任务追加到赋值在变量queue的”Dispatch Queue”中.

Dispatch Queue究竟是什么???

Dispatch Queue是执行处理的等待队列, 按照先进先出(FIFO, First-In-First-Out)的顺序进行任务处理.

First-In-First-Out

另外, 队列分两种, 一种是串行队列(Serial Dispatch Queue), 一种是并行队列(Concurrent Dispatch Queue).

Dispatch Queue的种类 说明
Serial Dispatch Queue 等待现在执行中处理结束
Concurrent Dispatch Queue 不等待现在执行中处理结束

串行队列

串行队列 : 让任务一个接一个执行

并行队列

并发队列 : 让多个任务同时执行(自动开启多个线程执行任务)
并发功能只有在异步函数(dispatch_async)下才有效(想想看为什么?)

GCD的API会在下面详细说明~


2. 什么是多线程, 并发

我们知道, 一个应用就相当于一个进程, 而一个进程可以同时分发几个线程同时处理任务.而并发正是一个进程开启多个线程同时执行任务的意思, 主线程专门用来刷新UI,处理触摸事件等 而子线程呢, 则用来执行耗时的操作, 例如访问数据库, 下载数据等..

以前我们CPU还是单核的时候, 并不存在真正的线程并行, 因为我们只有一个核, 一次只能处理一个任务. 所以当时我们计算机是通过分时也就是CPU地在各个进程之间快速切换, 给人一种能同时处理多任务的错觉来实现的, 而现在多核CPU计算机则能真真正正货真价实地办到同时处理多个任务.


3. GCD的优势

说到优势, 当然有比较, 才能显得出优势所在. 事实上, iOS中我们能使用的多线程管理技术有

  • pthread
  • NSThread
  • GCD
  • NSOperationQueue

pthread

来自Clang, 纯C语言, 需要手动创建线程, 销毁线程, 手动进行线程管理. 而且代码极其恶心, 我保证你写一次不想写第二次…不好意思我先去吐会T~T

NSThread :

Foundation框架下的OC对象, 依旧需要自己进行线程管理,线程同步。 线程同步对数据的加锁会有一定的开销。

GCD :

两个字, 牛逼, 虽然是纯C语言, 但是它用难以置信的非常简洁的方式实现了极其复杂的多线程编程, 而且还支持block内联形式进行制定任务. 简洁! 高效! 而且我们再也不用手动进行线程管理了.

NSOperationQueue :

相当于Foundation框架的GCD, 以面向对象的语法对GCD进行了封装. 效率一样高.

GCD优势在哪里?

  1. GCD会自动利用更多的CPU内核
  2. GCD会自动管理线程的生命周期
  3. 使用方法及其简单

怎么样? 心动不, 迫不及待想要知道怎么使用GCD了吧, 那我们马上切入正题~


4. GCD的API介绍

在介绍GCD的API之前, 我们先搞清楚四个名词: 串行, 并行, 同步, 异步

  • 串行 : 一个任务执行完, 再执行下一个任务
  • 并行 : 多个任务同时执行
  • 同步 : 在当前线程中执行任务, 不具备开启线程的能力
  • 异步 : 在新的线程中执行任务, 具备开启线程的能力

串行, 并行, 同步, 异步的关系

下面开始介绍GCD的API

创建队列

手动创建一个队列.

  • label : 队列的标识符, 日后可用来调试程序
  • attr : 队列类型
    DISPATCH_QUEUE_CONCURRENT : 并发队列
    DISPATCH_QUEUE_SERIAL 或 NULL : 串行队列

需要注意的是, 通过dispatch_queue_create函数生成的queue在使用结束后需要通过dispatch_release函数来释放.(只有在MRC下才需要释放)

并不是什么时候都需要手动创建队列, 事实上系统给我们提供2个很常用的队列.

主队列

该方法返回的是主线程中执行的同步队列. 用户界面的更新等一些必须在主线程中执行的操作追加到此队列中.

全局并发队列

该方法返回的是全局并发队列. 使用十分广泛.

  • identifier : 优先级
    DISPATCH_QUEUE_PRIORITY_HIGH : 高优先级
    DISPATCH_QUEUE_PRIORITY_DEFAULT : 默认优先级
    DISPATCH_QUEUE_PRIORITY_LOW : 低优先级
    DISPATCH_QUEUE_PRIORITY_BACKGROUND : 后台优先级
  • flags : 暂时用不上, 传 0 即可

注意 : 对Main Dispatch Queue和Global Dispatch Queue执行dispatch_release和dispatch_retain没有任何问题. (MRC)

同步函数

在参数queue队列下同步执行block

异步函数

在参数queue队列下异步执行block(开启新线程)

时间

根据传入的时间(when)和延迟(delta)计算出一个未来的时间

  • when :
    DISPATCH_TIME_NOW : 现在
    DISPATCH_TIME_FOREVER : 永远(别传这个参数, 否则该时间很大)
  • delta : 该参数接收的是纳秒, 可以用一个宏NSEC_PER_SEC来进行转换, 例如你要延迟3秒, 则为 3 * NSEC_PER_SEC.

延迟执行

有了上述获取时间的函数, 则可以直接把时间传入, 然后定义该延迟执行的block在哪一个queue队列中执行.

苹果还给我们提供了一个在主队列中延迟执行的代码块, 如下