简介
- 介绍
GCD全名,Grand Central Dispatch,翻译为:多线程优化技术 - 作用
GCD能够自动管理线程的生命周期,我们只需要告诉GCD我们想要执行什么任务即可,而不用管理如何执行
GCD执行任务的两种方式
- 同步函数:只能在当前线程中执行任务,不具备开启新线程的能力
- 异步函数:可以在新的线程中执行任务,具备开启新线程的能力(特殊情况:在主队列中不会开启新线程)
GCD的两种队列
并行队列
允许多个任务并行(同时)执行,并行功能只有在异步函数下才有效
其获取方式有两种,一种是获取全局并行队列,一种是自定义并行队列
- 全局并行队列
参数说明:(1)long identifier:枚举类型,设置队列执行优先级(如下代码)(2)unsigned long flags:此参数暂时没有作用,置为0即可
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
dispatch_queue_t queue = dispatch_get_global_queue(<#long identifier#>, <#unsigned long flags#>)
- 自定义并行队列
参数说明:(1)const char * _Nullable label:队列的名字,注意因为GCD为C语言函数,所以说字符串不再为@”“,而是”“(2)dispatch_queue_attr_t _Nullable attr:队列的类型,并行队列为DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t queue = dispatch_queue_create("AnICoo1", DISPATCH_QUEUE_CONCURRENT);
串行队列
一个任务执行完毕后,再执行下一个任务,就像排队一样
- 主队列
主队列是GCD自带的一种比较特殊的串行队列,放在主队列中的任务都会在主队列中执行,但是需要注意:在主队列下的同步操作是不会执行的,因为会发生死锁现象
dispatch_queue_t queue = dispatch_get_main_queue();
- 自定义串行队列
参数同上并行队列,只是第一个参数为DISPATCH_QUEUE_SERIAL,设置为NULL也行
dispatch_queue_t queue = dispatch_queue_create("AnICoo1", DISPATCH_QUEUE_SERIAL);
GCD的应用场景
- 同步函数 + 串行队列
不会开启新的线程,任务顺序执行
dispatch_queue_t queue = dispatch_queue_create("AnICoo1", NULL);
dispatch_sync(queue, ^{
NSLog(@"1===%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2===%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3===%@",[NSThread currentThread]);
});
输出结果:
- 同步函数 + 并行队列
不会开启新的线程,任务顺序执行
dispatch_queue_t queue = dispatch_queue_create("AnICoo1", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"1===%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2===%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3===%@",[NSThread currentThread]);
});
输出结果:
- 异步函数 + 串行队列
会开启新的线程,但是只会开启一个新的线程,且任务顺序执行
dispatch_queue_t queue = dispatch_queue_create("AnICoo1", NULL);
NSLog(@"主线程a0===%@",[NSThread currentThread]);
dispatch_async(queue, ^{
NSLog(@"1===%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2===%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3===%@",[NSThread currentThread]);
});
输出结果:
- 异步函数 + 并行队列
会开启多个新的线程,且任务在新的线程中执行
dispatch_queue_t queue = dispatch_queue_create("AnICoo1", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"主线程a0===%@",[NSThread currentThread]);
dispatch_async(queue, ^{
NSLog(@"1===%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2===%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3===%@",[NSThread currentThread]);
});
输出结果:
GCD中线程间通信
在GCD中,线程之间可以进行嵌套操作,例如:我们可以将耗时的操作在新线程中执行,执行完毕后再回到主线程执行任务
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程
});
});
GCD常见的函数
延时执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后执行这里的代码...
});
一次性代码
保证一段代码在程序运行过程中只执行一次,但是不能用于懒加载中,可用于+ load
方法中;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只执行1次的代码(这里面默认是线程安全的)
});
栅栏函数
栅栏函数可以分割进程,只有当栅栏函数前的进程结束后,后面的进程才会开始,所以,栅栏函数也可以来决定异步函数并行队列的进程顺序
注意:系统的全局并行队列不能利用栅栏函数
dispatch_queue_t queue = dispatch_queue_create("hello", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1===%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2===%@",[NSThread currentThread]);
});
//栅栏函数
dispatch_barrier_async(queue, ^{
NSLog(@"++++++++");
});
dispatch_async(queue, ^{
NSLog(@"3===%@",[NSThread currentThread]);
});
输出结果: