简答的复习了一下GCD的一些简单操作,这里做一个笔记,方便以后查看。
- Dispatch Queue
- 自定义串、并行队列
- 程序进程缺省队列
- 主线程队列
- 同步/异步、串行/并行使用
- 死锁问题
- dispatch_after
- dispatch_group
Dispatch Queue
Serial Dispatch Queue
按添加进队列的顺序(先进先出)一个接一个的执行Concurrent Dispatch Queue
并发执行队列里的任务
1.1 自定义串、并行队列
并行队列:DISPATCH_QUEUE_CONCURRENT
串行队列:DISPATCH_QUEUE_SERIAL
//创建一个名称为‘com.company.xxx’的串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("com.company.xxx", DISPATCH_QUEUE_SERIAL);
//创建一个名称为‘com.xxx’的并行队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.company.xxx", DISPATCH_QUEUE_CONCURRENT);
Note:
1)参数一是队列的名称,一般是使用倒序的全域名。虽然可以不给队列指定一个名称,但是有名称的队列可以让我们在遇到问题时更好调试
2)当参数二为nil时返回Serial Dispatch Queue(串行队列)
,如上面那个例子,当指定为DISPATCH_QUEUE_CONCURRENT
时返回Concurrent Dispatch Queue(并行队列)
1.2 程序进程缺省队列
高优先级队列:DISPATCH_QUEUE_PRIORITY_HIGH
中优先级队列:DISPATCH_QUEUE_PRIORITY_DEFAULT
低优先级队列:DISPATCH_QUEUE_PRIORITY_LOW
//获取程序缺省并行队列,第二个参数固定为0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
Note:
1)需要注意的是,三个队列不代表三个线程,可能会有更多的线程。并发队列可以根据实际情况来自动产生合理的线程数,也可理解为dispatch队列实现了一个线程池的管理,对于程序逻辑是透明的。
2)获取Global Dispatch Queue
的时候可以指定优先级,可以根据自己的实际情况来决定使用哪种优先级
1.3 主线程队列
//获取主线程串行队列
dispatch_queue_t queue = dispatch_get_main_queue();
三者对比
队列 | 串行 | 并行 |
---|---|---|
自定义队列 | √ | √ |
程序缺省队列 | × | √ |
主线程队列 | √ | × |
Note:
一般只在需要更新UI时我们才获取Main Dispatch Queue
,其他情况下用Global Dispatch Queue
就满足需求了
同步/异步、串行/并行使用
//异步执行block,函数立即返回
dispatch_async(queue, ^{
//block具体代码
});
//同步执行block,函数不返回
dispatch_sync(queue, ^{
//block具体代码
});
举例:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//子线程中开始网络请求数据
···
//更新数据模型
dispatch_sync(dispatch_get_main_queue(), ^{
//在主线程中更新UI代码
self.view.backgroundColor = [UIColor orangeColor];
});
});
Note:
尽可能避免使用dispatch_sync
,嵌套使用时还容易引起程序死锁
死锁问题
- 同步串行会出现死锁,同步并行不会造成死锁
- 异步不管是串行还是并行都不会出现死锁
- 异步嵌套同步或者同步嵌套异步就需要注意代码执行顺序
Note:
死锁原因:提交到主线程队列的时候,慎用同步dispatch_sync
方法,有可能造成死锁。因为主线程队列是串行队列,要等队列里的任务一个一个执行。所以提交一个任务到队列,如果用同步方法就会阻塞住主线程,而主线程又要等主线程队列里的任务都执行完才能执行那个刚提交的,所以主线程队列里还有其他的任务的话,但他已经被阻塞住了,没法先完成队列里的其他任务,即,最后一个任务也没机会执行到,于是造成死锁。
dispatch_after
dispatch_after
能让我们添加进队列的任务延时执行,比如想让一个Block在5秒后执行:
double delayTime = 5.0;
dispCatch_time_t dTime = dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(delayTime*NSEC_PER_SEC));
dispatch_after(dTime, dispatch_get_main_queue(), ^{
//delayTime秒后执行block块
NSLog(@"block执行");
});
dispatch_after
的真正含义是在5秒后把任务添加进队列中,并不是表示在5秒后执行,大部分情况该函数能达到我们的预期,只有在对时间要求非常精准的情况下才可能会出现问题
【拓展】
延迟执行还有另外一种方式,那就是NSObject中的performSelector:withObject:afterDelay:
以及performSelector:withObject:afterDelay:inModes:
dispatch_group
我们现在有3个Block要执行,我们不在乎它们执行的顺序,我们只希望在这3个Block执行完之后再执行某个操作。这个时候就需要使用dispatch_group
了
dispatch_group_t groupQueue = dispatch_group_create();
dispatch_group_async(groupQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"1");
});
dispatch_group_async(groupQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"2");
});
dispatch_group_async(groupQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"3");
});
dispatch_group_notify(groupQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"completion");
});
在控制台打印的结果是:
2015-07-21 22:17:57.159 GCD[9606:1327380] 3
2015-07-21 22:17:57.159 GCD[9606:1327377] 2
2015-07-21 22:17:57.159 GCD[9606:1327379] 1
2015-07-21 22:17:57.159 GCD[9606:1327377] completion
Note:
输出的顺序与添加进队列的顺序无关,因为队列是Concurrent Dispatch Queue
,但“completion”的输出一定是在最后的
再一次感谢您花费时间阅读这篇文章!
微博: @Danny_吕昌辉
博客: SuperDanny
2015 年 07月 15日