基本介绍
- Grand Central Dispatch 强大的中枢调度器
- 用于多线程
- 纯C语言
优势:
- 多核的并行运算
- 会自动利用更多的CPU内核
- 自动线程的生命周期(创建、调度、销毁)
- 程序猿只需告诉GCD想要执行什么任务,不需要编写任何线程管理代码
任务和队列
两个核心概念及 任务 和 队列
任务:执行什么操作
队列:用来存放任务
使用步骤
- 定制任务
- 确定想做的事情
- 将任务添加到队列中
- GCD会自动将队列中的任务取出,放到对应的线程中执行
- FIFO
执行任务
-
用同步的方式执行任务
-
用异步的方式执行任务
区别
- 同步:只能在当前线程中执行任务,不具备开启新线程的能力
- 异步:可以在新的线程中执行任务,具备开启新线程的能力 同步和异步的区别在于能不能开启新线程
并且这里的同步异步强调的是函数
队列的类型
- 并发队列 (Concurrent Dispatch Queue)
- 可以让多个任务并发执行(同时),自动开启多个线程同时执行任务
- 只有在异步函数下才有效
- 串行队列(Serial Dispatch Queue)
- 任务一个接一个的执行,必须是一个任务执行完毕后,再执行下一个任务 并发串行强调的是队列
GCD的基本使用
- 异步函数+并发队列
会开启多条线程,队列任务是并发执行的
两个函数的参数的含义
- 异步函数+串行队列 这种方式是会开启子线程的,但是只会开启一条子线程,并且任务是串行执行的
- 同步函数+并发队列
因为同步函数是不具备创建子线程的能力的,所以任务在主线程中执行,并且因为线程内部的任务是串行执行的,所以即使是并发队列,但是任务还是串行的
- 同步函数+串行队列
该情况和上一情况完全相同
除了按照上述的dispatch_queue_create
方法创建队列以外,还有一种获得全局并发队列的方式来获得队列
第一个参数是队列的优先级
这个是系统自身的队列,是本身就存在的,我们只是通过这个方法获得,而不是自己创建的
注意:GCD并不是说有多少个任务就开启多少个线程,GCD开启的线程数是不一定的,与任务数量没有一对一的关系
主队列
- 主队列是GCD自带的一种特殊的串行队列
- 放在主队列的任务,都会放到主线程中执行
- 使用
dispatch_get_amin_queue()
获得主队列
-
异步函数+主队列
-
同步函数+主队列
如果主队列发现当前主线程有任务在执行,那么主队列会暂停调度队列中的任务,直到主线程空闲为止
产生死锁:因为主线程正在执行syncMain函数,而这个函数中又在等待主线程执行完毕后再调用里面的同步函数,造成死锁
解决方式:在子线程中执行syncMain函数
各种队列的执行效果
其实可以看到就是异步函数的并发队列和串行队列情况较为特殊,其他都是一样的
反正你就记住
- 只要是同步的,就不会开启新线程
- 异步函数就可能会开启新线程
线程间的通信
以下载网络上的图片为例
- 因为下载图片是耗时操作,所以要放在子线程中去执行
- 那么图片下载后需要更新UI,之前说过,凡是和UI有关的操作都要在主线程中执行,如何从子线程回到主线程呢?
- 可以看到就是在子线程中通
dispatch_get_amin_queue()
获得主队列,因为主队列的任务必须在主线程中执行,因此我们实现了从子线程到主线程的通信
- 可以看到就是在子线程中通
- 在更新UI的时候如图选择异步函数,如果换成了同步函数会造成死锁吗?
- 不会,因为整个任务是在子线程中执行的,主线程此时没有任务,因此即使在这里使用同步函数也不会造成死锁
GCD的常用函数
延迟执行
- 第一种
performSelector
- 第二种
NSTimer
- 第三种
dispatch after
这是GCD提供的一种延迟执行方法
第一个参数:DISPATCH_TIME_NOW 从现在开始计算时间 第二个参数:延迟的时间 GCD的时间单位:纳秒 第三个参数:队列 第四个参数:block块,表示要执行的任务
这个方法相较于其他的延迟方法强大的地方在于GCD可以选择队列的种类
一次性代码
程序中只会执行一次的代码
一次性代码是不能放在懒加载里的
因为一次性代码只会执行一次,如果将懒加载放在里面,会导致第二次懒加载不会执行
一次性代码的应用适合单例模式