一. GCD的核心概念
-
什么是CGD
- GCD, 全称Grand Central Dispatch, 又称中枢调度器
- 他是Apple公司推出的, 使用纯C语言编写的(意味着性能的高效), 为多核的并行运算创建的牛X产物
- GCD会自动的利用多核的CPU, 达到更快速的调度线程, 更搞笑的执行任务
- CGD会自动的管理线程的声明周期, 如创建线程/调度任务/销毁线程
-
核心概念
- 任务: 线程需要去执行的操作, 方法, 代码段
- 队列: 用于存放任务的容器
- 任务添加并存放在队列中, 然后将队列中的任务, 根据函数调用的不同, 自发的分配给不同的线程去执行
- 并且任务的取出, 遵循队列的FIFO原则: 先进先出, 后进后出
-
同步和异步
-
同步:
dispatch_sync( queue队列, block任务 )
- 同步: 如果当前线程的任务没有执行完毕, 队列中的其他任务就会处于等待执行的状态
- 同步函数: 同步函数不具备开启新线程的能力, 他只能在当前的线程中去执行任务(在哪个线程中执行这个函数, 就在那个线程执行所有的任务)
-
异步:
dispatch_async( queue队列, block任务 )
- 异步: 当前线程中的任务没有执行完毕, 其他的线程也可以被调度去执行任务
- 异步函数: 具备开启线程的能力, 可以在新的线程中执行任务
-
二. GCD中的队列
-
并发和串行的概念
- 并发: 可让多个任务并发(同时)执行的队列, 他自动开启多个线程去执行任务
- 并发功能只有在异步函数(dispatch_async)下才会生效
- 串行: 让队列中的任务, 按顺序一个个地执行, 即一个任务执行完毕后, 在调度执行下一个任务
- 并发: 可让多个任务并发(同时)执行的队列, 他自动开启多个线程去执行任务
-
并发队列
创建一个并发队列:
dipatch_queue_t queue = dispatch_queue_create("队列名称", DISPATCH_QUEUE_CONCURRENT)
-
获取全局并发队列
dispatch_queue_t queueG = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 第一个参数: 队列的优先级, 分为High/Low/Default/Background 第二个参数: 暂未采用的参数, 始终传入0
GCD内部开启多少条线程, 是根据系统的当前情况自行决定的, 并不是根据任务的数量去开启对应的线程
-
串行队列
- 创建一个串行队列:
dispatch_queue_t queue = dispatch_queue_create("队列名称", DISPATCH_QUEUE_SERIAL)
- 获取主队列
- 凡是放在主队列中的任务, 都必须在主线程中执行
- 主队列是默认存在的队列, 并不是手动创建的
- 主队列在调度任务之前, 会检查主线程的状态, 如果主线程当前正在执行任务, 那么主队列就会停止调度队列中的任务
- 创建一个串行队列:
三. 线程. 队列和函数之间的组合(重要)
-
在并发队列中, 使用异步函数调度任务
任务的执行, 会开启新的线程
系统自行决定开启的线程的数量
-
任务会被分配到不同线程中并发执行
// 1. 并发队列,异步函数,每个异步函数开启了新的线程,并发执行任务 - (void)conAsync { // 1. 创建队列(并发队列) dispatch_queue_t queue = dispatch_queue_create("队列名称", DISPATCH_QUEUE_CONCURRENT); // 2. 使用函数封装任务,并把任务添加到队列中(异步) dispatch_async(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在并发队列中, 使用同步函数调度任务
同步函数执行的任务, 并不会开启新的线程, 都在主线程中执行
-
所有的任务串行执行
// 2. 并发队列,同步函数,不会开启新的线程,任务按照顺序串行执行 - (void)conSync { // 1. 创建普通的并发队列, 效果与全局并发队列相同 // dispatch_queue_t queue = dispatch_queue_create("adsfa", DISPATCH_QUEUE_CONCURRENT); // 1.1 创建全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); // 2. 封装任务,并添加到队列中(同步) dispatch_sync(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在串行队列中, 使用异步函数调度任务
异步函数具备开启子线程的能力, 因此会开启一条线程, 但是由于是串行队列, 因此只会开启一条新线程
-
所有的任务都在这个新线程中串行执行任务
// 3. 串行队列,异步函数,开启了一条子线程,队列中的任务是串行执行的 - (void)serAsync { // 1. 创建串行队列 dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_SERIAL); // 2. 使用异步函数封装任务 dispatch_async(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在串行队列中, 使用同步函数执行任务
同步函数不具备开启线程的能力, 因此所有任务是在主线程中执行的
-
串行队列中的任务, 是串行执行的
- (void)serSync { // 1. 创建串行队列 dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_SERIAL); // 2. 使用同步函数封装任务 dispatch_sync(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在主队列中, 使用异步函数调度任务
异步函数虽然具备开启线程的能力, 但是由于主队列中的任务只能在主线程中执行, 因此并不会开启新的线程
-
主队列也属于串行队列, 因此任务串行执行
- (void)mainAsync { // 1. 创建主队列 dispatch_queue_t queue = dispatch_get_main_queue(); // 2. 使用异步添加任务 dispatch_async(queue, ^{ NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }
-
在主队列中, 使用同步函数调度任务重中之重, 常考问题!!!
主队列中的任务都会放在主线程中执行
主队列的特性: 如果主线程目前有任务在处理, 处于忙碌状态, 那么主队列就会暂停调度任务
同步函数不具备开启新线程的能力, 因此同步函数的任务也只能在主线程中处理
当第一个同步函数, 放入主线程准备执行的时候, 这时主线程就会进入工作状态, 并且进入忙碌状态
-
这时主队列察觉到主线程正处于忙碌, 因此就会停止调度任务, 这时任务的调度停止了, 第一个进入主队列的同步函数也就停止了执行, 此时, 就会出现死锁状态, 变现为程序的死机
- (void)mainSync { // 1. 获取主队列 dispatch_queue_t queue = dispatch_get_main_queue(); NSLog(@"123"); // 2. 使用同步添加任务 dispatch_sync(queue, ^{ // 当开始处理第一个任务的时候, 主线程就已经挂掉了 NSLog(@"1---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"2---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"3---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"4---%@", [NSThread currentThread]); }); }