简述
GCD
为苹果推出的多核编程解决方案,它不仅能够自动利用多个核心处理数据,还能够自动管理生命周期,不需要程序猿手动管理。在日常的编程中十分常用。
创建队列
使用 GCD
首先需要创建或获取一个队列,可以使用 dispatch_queue_create
-
创建一个队列,具体代码:
dispatch_queue_t queue = dispatch_queue_create("SERIALQUEUE", DISPATCH_QUEUE_SERIAL);dispatch_queue_t queue = dispatch_queue_create("CONCURRENTQUEUE", DISPATCH_QUEUE_CONCURRENT);复制代码
第一个参数为队列的唯一标识符,第二个参数表示该队列是并发队列还是串行队列。
-
DISPATCH_QUEUE_SERIAL : 表示串行队列
-
DISPATCH_QUEUE_CONCURRENT : 表示并发队列
-
-
获取一个队列,具体代码:
// 获取主队列dispatch_queue_t queue = dispatch_get_main_queue(); // 获取全局并发队列dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);复制代码
获取全局并发队列中的第一个参数表示队列的优先级,填入
DISPATCH_QUEUE_PRIORITY_DEFAULT
即可,第二个参数 0 即可。
创建任务
GCD创建任务分为两种:
- 同步任务
- 异步任务
创建方式分别如下:
// 同步任务dispatch_sync(queue, ^{ // code});// 异步任务dispatch_async(queue, ^{ // code});复制代码
同步和异步的区别是,异步允许开启新的线程,而同步不允许。串行和并发的区别是,串行只开启一条线程,并发能开启一条以上的线程。这就导致了:
- 同步 + 并发 : 只开启一条线程,任务按顺序进行
- 同步 + 串行 : 只有一条线程,任务按顺序进行
- 异步 + 并发 : 开启多条线程,任务同时进行
- 异步 + 串行 : 只有一条线程,任务按顺序进行
主队列 + 同步会造成死锁,如以下代码。
dispatch_queue_t queue = dispatch_get_main_queue();NSLog(@"1");dispatch_sync(queue, ^{ NSLog(@"2");});NSLog(@"3");复制代码
以上代码只会输出 1 不会输出 2 ,3。
至于主队列 + 异步相当于串行 + 异步,只有一条线程,任务按顺序进行。全局并发队列与普通并发队列类似不再赘述。
GCD线程间的通信
试想这种场景,异步请求数据并且加载完 model 后,现在想回到主线程用更新好的 model 刷新视图。这个时候就要用到线程之间的通信。实现起来很简单,只需要在任务代码后再异步给主线程添加一个任务即可。如:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ // code // 回到主线程 dispatch_async(dispatch_get_main_queue(), ^{ // code });});复制代码
GCD其他用法
dispatch_after 延迟执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // code}复制代码
其中的代码会在大约5秒后执行,为什么用大约,因为实际上不是很精确,但是对于延迟几秒执行代码,这个方法还是非常好用的。
dispatch_once 单次执行
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // code});复制代码
内部的代码只会执行一次,并且是线程安全的。这个方法经常被用来编写单例使用,如:
// 单例+ (instancetype)shareInstance { static Class * object = nil; static dispatch_once_t onceTocken; dispatch_once(&onceTocken, ^{ object = [Class new]; }); return object;}复制代码
dispatch_barrier_async 栅栏任务
在两个异步任务中添加栅栏任务,能够将两者分开执行,而栅栏任务在两者之间执行。 使用方法如下:
dispatch_async(queue, ^{ // code1 });dispatch_barrier_async(queue, ^{ // code });dispatch_async(queue, ^{ // code2 });复制代码
这样使用后,code1 和 code2 就会分离执行了。