苹果官方给出的解释:GCD是异步执行任务的技术之一。一般将应用程序中记述的线程管理代码在系统集中实现,开发者只需要定义想执行的任务并追加到适当的Dispatch
Queue中,GCD就可以生成必要的线程并计划执行任务。
GCD的概念
GCD 是Grand Central Dispatch的缩写,是苹果对多核硬件上执行并发代码的一种支持。GCD有一下特点
- GCD通过把计算密集型任务放于后台运行,以此提高APP的响应速度(多线程)
- GCD提供了更简单的并发模型,它优于线程锁,并且帮助你避免并发bug。(安全)
- GCD基于底层、高性能的优化常规类型的代码,例如单例。(高效)
- GCD代码简洁,使用方便(简洁)
GCD的术语
GCD的概念主要包括串行,并行,同步,异步,危险区,竞态条件,死锁,线程安全,环境切换.
概念 | 作用 | 通俗解释 |
---|---|---|
串行 | 事件按顺序执行 | A - B - C |
并行 | 事件可以同时发生 | A/B/C |
同步 | 不开启新的线程 | 只有代码块完成了才可以继续执行 |
异步 | 开启新的线程 | 可以继续执行 |
危险区 | 共享代码区 | 临界区 |
竞态条件 | 共享代码区别访问 | 数据会发生破坏 |
死锁 | 任务和线程的相互等待 | 循环等待 |
线程安全 | 数据不可以被多个线程访问 | NSDictionary |
环境切换 | 线程切换执行状态恢复和处理 | 多任务App |
GCD的实验
实验1 串行 + 同步
NSLog(@"线程:%@开始看延禧攻略",[NSThread currentThread]);
//串行
dispatch_queue_t queue = dispatch_queue_create("SERIAL_1", DISPATCH_QUEUE_SERIAL);
//同步
dispatch_sync(queue, ^{
NSLog(@"线程:%@正在看延禧攻略",[NSThread currentThread]);
});
NSLog(@"线程:%@看完了延禧攻略",[NSThread currentThread]);
2018-08-17 15:41:15.051488+0800 TestGCD[8476:227832] 线程:<NSThread: 0x604000070b80>{number = 1, name = main}开始看延禧攻略
2018-08-17 15:41:15.051628+0800 TestGCD[8476:227832] 线程:<NSThread: 0x604000070b80>{number = 1, name = main}正在看延禧攻略
2018-08-17 15:41:15.051735+0800 TestGCD[8476:227832] 线程:<NSThread: 0x604000070b80>{number = 1, name = main}看完了延禧攻略
专家分析:
- 先执行 ==开始看延禧攻略==
- 判断为同步执行,执行 ==正在看延禧攻略==
- 执行==看完了延禧攻略==
<html>
<p style="color:red;">注意:虽然有两个线程,但任务要按顺序取出来,所以也只能执行一个任务</p>
</html>
实验2 串行 + 异步
NSLog(@"线程:%@开始看延禧攻略",[NSThread currentThread]);
//串行
dispatch_queue_t queue = dispatch_queue_create("SERIAL_1", DISPATCH_QUEUE_SERIAL);
//异步
dispatch_async(queue, ^{
NSLog(@"线程:%@正在看延禧攻略",[NSThread currentThread]);
});
NSLog(@"线程:%@看完了延禧攻略",[NSThread currentThread]);
2018-08-17 15:52:04.038083+0800 TestGCD[8799:238132] 线程:<NSThread: 0x60000007c800>{number = 1, name = main}开始看延禧攻略
2018-08-17 15:52:04.038267+0800 TestGCD[8799:238132] 线程:<NSThread: 0x60000007c800>{number = 1, name = main}看完了延禧攻略
2018-08-17 15:52:04.038299+0800 TestGCD[8799:238199] 线程:<NSThread: 0x60c000260340>{number = 3, name = (null)}正在看延禧攻略
专家分析:
- 先执行 ==开始看延禧攻略==
- 判断为串行队列,将 ==正在看延禧攻略== 追加到串行队列后面,这个时候顺序为 ==开始看延禧攻略== ==看完了延禧攻略== ==正在看延禧攻略== ;判断为异步执行,新开启一个线程)
- 从串行队列取出任务依次执行
实验3 并行 + 同步
NSLog(@"线程:%@开始看延禧攻略",[NSThread currentThread]);
//并行
dispatch_queue_t queue = dispatch_queue_create("SERIAL_1", DISPATCH_QUEUE_CONCURRENT);
//异步
dispatch_sync(queue, ^{
NSLog(@"线程:%@正在看延禧攻略",[NSThread currentThread]);
});
NSLog(@"线程:%@看完了延禧攻略",[NSThread currentThread]);
2018-08-17 16:19:18.103827+0800 TestGCD[9522:258973] 线程:<NSThread: 0x600000261b40>{number = 1, name = main}开始看延禧攻略
2018-08-17 16:19:18.104044+0800 TestGCD[9522:258973] 线程:<NSThread: 0x600000261b40>{number = 1, name = main}正在看延禧攻略
2018-08-17 16:19:18.104147+0800 TestGCD[9522:258973] 线程:<NSThread: 0x600000261b40>{number = 1, name = main}看完了延禧攻略
专家分析:
- 先执行 ==开始看延禧攻略==
- 判断为并行队列,将 ==正在看延禧攻略== 追加到一个新的队列里面;判断为同步执行,所以只有一个线程
- 只有一个线程,先从队列1取出==开始看延禧攻略==,再从队列2取出 ==正在看延禧攻略==,再从队列1取出 ==看完了延禧攻略==
<html>
<p style="color:red;">注意:虽然有两个任务队列,但只有一个线程,所以也只能执行一个任务</p>
</html>
实验4 并行 + 异步
NSLog(@"线程:%@开始看延禧攻略",[NSThread currentThread]);
//并行
dispatch_queue_t queue = dispatch_queue_create("SERIAL_1", DISPATCH_QUEUE_CONCURRENT);
//异步
dispatch_async(queue, ^{
NSLog(@"线程:%@正在看延禧攻略",[NSThread currentThread]);
});
NSLog(@"线程:%@看完了延禧攻略",[NSThread currentThread]);
2018-08-17 16:38:38.335505+0800 TestGCD[10077:274421] 线程:<NSThread: 0x60c000261e80>{number = 1, name = main}开始看延禧攻略
2018-08-17 16:38:38.335701+0800 TestGCD[10077:274421] 线程:<NSThread: 0x60c000261e80>{number = 1, name = main}看完了延禧攻略
2018-08-17 16:38:38.335727+0800 TestGCD[10077:274480] 线程:<NSThread: 0x60400026a780>{number = 3, name = (null)}正在看延禧攻略
专家分析:
- 先执行 ==开始看延禧攻略==
- 判断为并行队列,将 ==正在看延禧攻略== 追加到一个新的队列里面;判断为同步执行,有两个线程
- 两个线程分别从两个队列取出任务去执行
实验5 主队列 + 同步
NSLog(@"线程:%@开始看延禧攻略",[NSThread currentThread]);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"线程:%@正在看延禧攻略",[NSThread currentThread]);
});
NSLog(@"线程:%@看完了延禧攻略",[NSThread currentThread]);
2018-08-17 16:49:11.267733+0800 TestGCD[10403:283929] 线程:<NSThread: 0x608000069840>{number = 1, name = main}开始看延禧攻略
崩溃
实验6 主队列 + 异步
NSLog(@"线程:%@开始看延禧攻略",[NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"线程:%@正在看延禧攻略",[NSThread currentThread]);
});
NSLog(@"线程:%@看完了延禧攻略",[NSThread currentThread]);
2018-08-17 16:59:03.154983+0800 TestGCD[10697:291985] 线程:<NSThread: 0x60c000062fc0>{number = 1, name = main}开始看延禧攻略
2018-08-17 16:59:03.155130+0800 TestGCD[10697:291985] 线程:<NSThread: 0x60c000062fc0>{number = 1, name = main}看完了延禧攻略
2018-08-17 16:59:03.158271+0800 TestGCD[10697:291985] 线程:<NSThread: 0x60c000062fc0>{number = 1, name = main}正在看延禧攻略
总结:队列分串行和并行,每个队列相当于一个线性的任务表单。执行方式分同步和异步,相当于执行的物理单元。
下面以指压板(奔跑吧)为例子
同步 + 串行:
假设奔跑吧里面:anglebaby拿到指压板任务清单,将任务按顺序去完成,先跳绳-赛跑-跨栏-仰卧爬行
同步 + 并行:
假设奔跑吧里面:anglebaby拿到指压板任务清单1和清单2,先完成清单1 跳绳-赛跑,再完成清单2 ,跨栏-仰卧爬行
异步 + 串行:
假设奔跑吧里面:anglebaby和邓超上场,只有anglebagy拿到指压板任务清单,,先跳绳-赛跑-跨栏-仰卧爬行,邓超作为新的线程没有任务可以完成
异步 + 并行:anglebaby和邓超上场,只有anglebagy拿到指压板任务清单1,跳绳-赛跑,邓超作为新的线程拿到清单2,完成跨栏,仰卧爬行
网友评论