GCD编程探索(一)

 苹果官方给出的解释: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,完成跨栏,仰卧爬行
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容