简述
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 就会分离执行了。