GCD核心概念
- 任务 :执行GCD函数block(代码块)中的代码
- 队列 :用来存放任务的队列,遵循FIFO原则
队列(Queue)详解
-
GCD队列有两种:1、串行队列(Serial Queues) ,2、并发队列(Concurrent Queues)
-
串行队列 : 让任务按照队列次序依次地执行(一个任务执行完毕后,再执行下一个任务),该队列每次只能执行一个任务,只有当队头的任务执行完毕后从队列中移除,才会继续执行下一个任务。
例子:排队卖票。 -
并发队列 : 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)。添加到并发队列中的任务,依然会依次按照任务开始加入队列的次序执行,但是,任务执行的过程都同步进行,不需要等待。并发队列保证任务开始执行的次序是确定的,但是你无法知道执行的次序,执行时长或在任意时间点同步执行的任务个数。
队列使用
- 系统队列:系统(“系统”指所有被苹果黑盒封装,未公开源码,我们不能得知的操作,下同)为每个应用提供了一个串行队列与四个并发队列。
- 主队列:为串行队列,在应用的主线程中执行任务,该队列用于更新应用的 UI,执行与 UIViews 更新相关的所有任务。因此每次只能执行一个任务,所以当你在主队列运行繁重的任务时,UI 就会停止响应。
dispatch_get_main_queue()
- 四个并发队列:我们称之为全局队列,拥有四个不同的优先级。
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)//第二个参数无用,苹果用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_create
来创建对象,需要传入两个参数,第一个参数表示队列的唯一标识符,用于DEBUG,可为空;第二个参数用来识别是串行队列还是并发队列。DISPATCH_QUEUE_CONCURRENT
表示并发队列。DISPATCH_QUEUE_SERIAL
表示串行队列。
// 串行队列的创建方法
dispatch_queue_t queue= dispatch_queue_create("bluajack", DISPATCH_QUEUE_SERIAL);
// 并发队列的创建方法
dispatch_queue_t queue= dispatch_queue_create("bluajack", DISPATCH_QUEUE_CONCURRENT);
GCD函数创建任务
- 创建方法
// 同步执行任务创建方法
dispatch_sync(queue, ^{ NSLog(@"%@",[NSThread currentThread]); // 这里放任务代码});
// 异步执行任务创建方法
dispatch_async(queue, ^{ NSLog(@"%@",[NSThread currentThread]); // 这里放任务代码});
- 函数和队列组合方式
- ```objc
同步执行 + 串行队列 (不会开启子线程,串行执行任务)
同步执行 + 并发队列 (不会开启子线程,串行执行任务)
异步执行 + 串行队列 (开启子线程,串行执行任务)
异步执行 + 并发队列 (开启子线程,并行执行任务)
//特殊队列- 主队列
同步执行 + 主队列 (不会开启子线程,串行执行任务)
异步执行 + 主队列 (不会开启子线程,串行执行任务)
```
- 归纳
- 1.同步GCD函数执行任务,无论添加的是串行队列还是并发队列,都不会创建子线程,但都会在创建任务后,立刻在当前线程依次按队列先进先出(FIFO)顺序执行任务。
- 2.主队列是一个特殊的队列,无论是GCD同步函数还是异步函数执行任务,都不会创建子线程。
##分析主队列 + 异步
- 先贴代码和控制台信息
- ```objc
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1");
//同步GCD函数,无论是串行队列还是并发队友,都不会创建子线程,但都会在创建后,立刻在当前线程依次按队列FIFO顺序执行任务。
//主队列是一个特殊的队列,无论是GCD同步函数还是异步函数,都不会创建子线程
//所以只有在主线程执行完主队列里面的内容,空闲时,才能去执行你创建的队列。
dispatch_async(dispatch_get_main_queue(), ^{
for (int i = 0; i<5; i++) {
NSLog(@"222222222%@",[NSThread currentThread]);
}
});����
for (int i = 0; i<5; i++) {
NSLog(@"3");
}
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
for (int i = 0; i<5; i++) {
NSLog(@"4");
}
}
- (void)viewDidAppear:(BOOL)animated{
TestViewController *VC = [[TestViewController alloc] init];
//一直到modal方法结束后,才能在主线程去执行你创建的队列
//我猜测modal方法内部,是执行了VC控制器的loaView懒加载方法,初始化view,一并执行了viewDidLoad方法
//交给系统GPU去渲染,然后此时CPU得到空闲,就会去执行我在本控制器内部用GCD在主队列中创建的任务,
//然后我创建的任务执行完毕,就会继续执行主队列的内容,GPU渲染完毕,通知CPU进行视图的显示,
//此时就会调用VC的viewWillAppear的代理方法。
[self presentViewController:VC animated:YES completion:nil];
}
**2016-11-23 17:06:23.207 test-GCD死锁[14103:166127] 1
**2016-11-23 17:06:23.207 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.207 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.209 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.209 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.213 test-GCD死锁[14103:166127] -[TestViewController viewDidLoad]
**2016-11-23 17:06:23.577 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.578 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.578 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.578 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.578 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.580 test-GCD死锁[14103:166127] -[TestViewController viewWillAppear:]
- 把上述代码创建的GCD函数内部的代码块的for循坏,加到10000次,你就能很明显的感觉到页面跳转的延迟,这就造成主线程的阻塞。
##GCD死锁
- 典型例子:在主线程中用GCD创建同步 + 主队列函数
- ```objc
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"2%@",[NSThread currentThread]);
});����
NSLog(@"3");
}
输出结果为:1 。这个程序就是典型的死锁,只打印了“1”一行,就再也没有响应了,已经造成了GCD死锁。
下班了,具体分析,你们可以看下面这篇文章,比较详细。
http://www.jianshu.com/p/bbabef8aa1fe
网友评论