简介
- GCD(Grand Center Dispatch)是Apple为多核的并行运算提出的解决方案,纯C语言
- 更加适配多核处理器,且自动管理线程的生命周期,使用起来较为方便
- GCD通过任务和队列实现多线程功能
- 任务:描述所要执行的操作
- 队列:用来存放所要执行的任务,队列中的任务遵循FIFO(First In First Out)原则
GCD的任务函数(是否开启新的线程)
-
同步
- 不具备开启新的线程的能力
- 同步执行任务的函数
- void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block),Block类型
- queue:任务队列
- block(代码块):所执行的任务
- void dispatch_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work),函数类型(每个Block类型都对应一个函数类型)
- queue:任务队列
- context:传递给任务函数的参数
- work(函数):所执行的任务
- void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block),Block类型
- 同步执行任务的其他函数(barrier),在前面的任务执行完毕它才执行,它后边的任务等它执行完毕才执行
- void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block),block类型
- queue:任务队列,仅当该参数为并发队列时,该函数才有意义
- dispatch_barrier_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work),函数类型
- void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block),block类型
-
异步
- 具备开启新的线程的能力(需要将任务添加到并发队列中)
- 异步执行任务的函数(参数意义与同步函数相同)
- void dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
- void dispatch_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work)
- 异步执行任务的其他函数(barrier),在前面的任务执行完毕它才执行,它后边的任务等它执行完毕才执行(参数意义与同步函数相同)
- void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block)
- void dispatch_barrier_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work)
GCD的队列(任务的执行方式)
- 并发队列
- 开启多个线程,使队列中的多个任务并发执行(需要异步执行函数的配合)
- 串行队列
- 队列中的任务一个接一个顺序地执行
- 队列的种类
- 串行队列
- dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
- label:通常为0
- attr:队列类型,DISPATCH_QUEUE_SERIAL
- dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
- 并发队列
- dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
- label:通常为0
- attr:队列类型 DISPATCH_QUEUE_CONCURRENT
- dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
- 主队列(串行,只能在主线程中运行)
- dispatch_queue_t dispatch_get_main_queue(void),获取主队列
- 全局队列(并发)
- dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags)
- 串行队列
任务与队列的组合
- 同步函数
-
同步函数主队列
/** - 运行在主线程主队列(未开启新的线程),主线程被卡死 - 原因:任务代码等待着当前函数执行完毕才能执行(当前函数正在执行且未执行完毕); 当前函数等待着任务代码 执行完毕才能执行(当前任务正在执行且未执行完毕); 相互等待,出现死锁 */ //获取主队列 dispatch_queue_t queue = dispatch_get_main_queue(); //添加任务到队列 dispatch_sync(queue, ^{ //任务1代码 }); dispatch_sync(queue, ^{ //任务2代码 });
-
同步函数串行队列
/** - 运行在主线程串行非主队列(未开启新的线程),任务串行执行 */ //创建串行队列 dispatch_queue_t queue = dispatch_queue_create("com.23565@qq", DISPATCH_QUEUE_SERIAL); //添加任务到队列 dispatch_sync(queue, ^{ //任务1代码 }); dispatch_sync(queue, ^{ //任务2代码 });
-
同步函数并发队列
/** - 运行在非主线程并发队列(未开启新的线程),任务串行执行 */ //获取全局队列(并发) dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //将任务加至队列 dispatch_sync(queue, ^{ //任务1代码 }); dispatch_sync(queue, ^{ //任务2代码 });
-
- 异步函数
-
异步函数主队列
/** - 运行在主线程主队列(未开启新的线程),任务串行执行 */ // 获得主队列 dispatch_queue_t queue = dispatch_get_main_queue(); // 将任务加入队列 dispatch_async(queue, ^{ //任务1代码 }); dispatch_async(queue, ^{ //任务2代码 });
-
异步函数串行队列
/** - 运行在主函数串行非主队列(未开启新的线程),任务串行执行 */ //创建串行队列 dispatch_queue_t queue = dispatch_queue_create("com.23565@qq", DISPATCH_QUEUE_SERIAL); //将任务加至队列 dispatch_async(queue, ^{ //任务1代码 }) dispatch_async(queue, ^{ //任务2代码 })
-
异步函数并发队列
/** - 运行在非主线程并发队列(开启新的线程),任务并发执行 - 系统根据任务创建线程(无法确定任务执行在哪个线程) */ //获得全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //将任务加入队列 dispatch_async(queue, ^{ //任务1代码 }); dispatch_async(queue, ^{ //任务2代码 });
-
线程之间的通信
- 从主线程到子线程
-
注意
- 只有异步函数与并发队列的组合,才会开启新的线程,使任务并发执行
- 通常使用异步函数将任务添加到并发队列中,来实现从主线程到子线程的通信
-
实现代码
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //需要在子线程中执行的任务代码 })
-
- 从子线程到主线程
-
注意
- 主队列中的任务只能在主线程中执行
- 通常使用异步/同步函数将任务添加到主队列中,来实现从子线程到主线程的通信
-
实现代码
dispatch_async(dispatch_get_main_queue(), ^{ //需要在主线程中执行的代码 })
-
GCD的其他任务
-
单次执行(通常用在单例模式的设计中)
//定义一个标记 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //此处的代码只会被执行一次 });
-
延迟执行
/** - 方法一(GCD) */ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //此处的代码将延迟执行 }); /** - 方法二(performSelector) */ [self performSelector:@selector(run) withObject:self afterDelay:2.0]; /** - 方法三(NSTimer) */ [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO]
-
快速迭代
void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t)) /** iterations:迭代执行的次数 queue:任务队列 block:迭代执行的代码 size_t:用来定义当前迭代到第几次,需要自己添加,如在size_t后添加index索引,记录当前的迭代次数 */
-
Barrier
/** - Barrier中的任务,只能在它前面的任务执行完毕才能执行 Barrier后的任务,只能等到它执行完毕才能执行 - 要将队列添加到自己创建的并发队列中,否其功能等同于函数 void dispatch_async(dispatch_queue_t queue, dispatch_block_t block) */ //创建队列(通常是自己创建的并发队列) dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_CONCURRENT); //将任务添加到队列 dispatch_async(queue, ^{ //在Barrier前执行的任务代码 }); dispatch_barrier_async(queue, ^{ //Barrier中的任务代码 }); dispatch_async(queue, ^{ //在Barrier后执行的任务代码 });
-
队列组
//获取全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //创建队列组 dispatch_group_t group = dispatch_group_create(); //添加任务到队列组 dispatch_group_async(group, queue, ^{ //任务1代码 }); dispatch_group_async(group, queue, ^{ //任务2代码 }); dispatch_group_notify(group, queue, ^{ //任务3代码 /** group组中的所有任务执行完毕在执行 若group为空,则立即执行 */ });
##GCD定时器
---
- 实现原理
- 创建一个DISPATCH_SOURCE_TYPE_TIMER类型的dispatch source,并添加到dispatch queue,通过dispatch source来响应事件
- 通过函数void dispatch_source_set_timer(dispatch_source_t source, dispatch_time_t start, uint64_t interval, uint64_t leeway),来设置dispatch source的执行事件
- 实现代码
```
//获得队列
dispatch_queue_t queue = dispatch_get_main_queue();
//创建一个定时器
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//设置定时器的各种属性(起止时间)
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(8.0 * NSEC_PER_SEC));
uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
//设置
dispatch_source_set_timer(self.timer, start, interval, 0);
//设置回调
dispatch_source_set_event_handler(self.timer, ^{
//定时器被触发时所要执行的代码
});
//开启定时器
dispatch_resume(self.timer);
//取消定时器
dispatch_cancel(self.timer);
```