UDN-企业互联网技术人气社区

板块导航

浏览  : 1641
回复  : 0

[资讯] GCD串行并发队列扫盲

[复制链接]
芭芭拉的头像 楼主
发表于 2017-1-18 16:04:37 | 显示全部楼层 |阅读模式
  概述

  本篇一起来学习GCD队列相关知识及如何使用。一直以来都是看到过别人这么用,说实在的,还真没有学过文档,也没有深入研究过其所以然。今天一起来看看苹果的GCD队列相关知识,扫一扫盲区吧!

  学习完本篇,您会对以下知识点更加理解:

  • 队列
  • 串行队列
  • 并发队列
  • GCD全局队列
  • GCD主队列
  • 创建串行队列
  • 创建并发队列

  队列基础知识 

  在大学学习过队列、栈数据结构吧?如果学习过,应该是非常容易理解的。不管是什么队列,一定是FIFO队列,即先进先出。

  所以,请大家记住了:不管是串行队列(SerialQueue)还是并发队列(ConcurrencyQueue),都是FIFO队列。也就意味着,任务一定是一个一个地,按照先进先出的顺序来执行。

  串行队列:在创建队列时,传参数DISPATCH_QUEUE_SERIAL表示创建串行队列。任务会一个一个地执行,只有前一个任务执行完成,才会继续执行下一个任务。 串行执行并不是同步执行的意思,一定要注意区分

  并发队列:在创建队列时,传参数DISPATCH_QUEUE_CONCURRENT表示创建并发队列。并发队列会尽可能多地创建线程去执行任务。并发队列中的任务会按入队的顺序执行任务,但是哪个任务先完成是不确定的。

  队列类型

  苹果提供了以下队列:

  • 全局队列:苹果预定义的全局并发队列,只能通过苹果提供的API来获取,可以设置优先级。
  • 主队列:在应用启动的时候,就会自动创建与主线程关联的串行队列,我们也可能获取,不能手动创建。
  • 手动创建串行队列
  • 手动创建并发队列

  全局队列

  全局队列的第二个参数用于设置优先级,只有下面四个选项:

  1. /*
  2. #define DISPATCH_QUEUE_PRIORITY_HIGH 2
  3. #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
  4. #define DISPATCH_QUEUE_PRIORITY_LOW (-2)
  5. #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
  6. */
复制代码

  我们通常使用默认选项,所以很多时候看到的都是传0。下面我们来看看创建四个任务放到并发队列中异步地执行:
  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  2.   NSLog(@"1");
  3. });
  4. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  5.   // 睡眠2秒
  6.   sleep(2);
  7.   NSLog(@"2");
  8. });

  9. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  10.   // 睡眠3秒
  11.   sleep(1);
  12.   NSLog(@"3");
  13. });
复制代码

  打印结果如下:
1.png

  打印出来的队列是通过dispatch_get_current_queue来获取当前正在执行任务的队列,也就是主队列了。不过这个API已经在6.0以后被标识为DEPRECATED(废弃)了。

  上面的代码中,我们在并发队列中添加了三个任务,其中任务1是直接执行,任务2是在异步执行过程中被睡眠2秒,任务3在异步执行过程中被睡眠1秒,结果任务3先于任务2执行完成。说明并发执行任务并不需要等待其他任务先执行完。对于这三个任务,是互不干扰的!

  当然,全局队列可以指定任务执行的优先级的,比如下面:
  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
  2.   NSLog(@"4");
  3. });

  4. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
  5.   NSLog(@"3");
  6. });

  7. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  8.   NSLog(@"2");
  9. });

  10. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
  11.   NSLog(@"1");
  12. });
复制代码

  打印如下:
1.png

  任务四优先级最高,所以在并发队列中优先执行。

  提示:暂时忽略dispatch_async,后续文件会学习

  主队列

  主队列是应用程序启动时,由系统预先创建的,与主线程相关联的队列。我们只能通过系统API来获取主队列,不能手动创建它。下面我们来看看主队列这个串行队列的执行顺序如何:
  1. dispatch_async(dispatch_get_main_queue(), ^{
  2.     sleep(2);
  3.     NSLog(@"main 1");
  4. });
  5.   
  6. dispatch_async(dispatch_get_main_queue(), ^{
  7.     NSLog(@"main 2");
  8. });
  9.   
  10. dispatch_async(dispatch_get_main_queue(), ^{
  11.     sleep(1);
  12.     NSLog(@"main 3");
  13. });
复制代码

  打印结果
1.png

  从打印结果可看到执行的顺序是按入队的顺序来执行的。虽然让任务1睡眠2秒再执行,其他任务也只能等待任务1完成,才能继承执行任务2,在任务2执行完成,才能执行任务3。

  从打印结果可以看到线程号是固定的,说明都在同一个线程中执行,而这个线程就是主线程。任务只能一个一个地执行。

  提示:暂时忽略dispatch_async,后续文件会学习

  创建串行队列

  通过dispatch_queue_create函数来创建队列,参数一是一个C语言的字符串,是队列的标签,也就是名称,通常是采用com..这样的格式。参数二是指定串行队列还是并发队列。

  • 创建串行队列传:DISPATCH_QUEUE_SERIAL(也就是NULL)
  • 创建并发队列传:DISPATCH_QUEUE_CONCURRENT

  一起来看看串行队列是否需要等待任务执行完成,下一个任务才能开始:

  1. // 串行队列
  2. dispatch_queue_tconcurrencyQueue = dispatch_queue_create("com.huangyibiao.concurrency-queue",
  3.                                                           DISPATCH_QUEUE_SERIAL);
  4. dispatch_async(concurrencyQueue, ^{
  5.   NSLog(@"s1");
  6. });
  7. dispatch_async(concurrencyQueue, ^{
  8.   sleep(2);
  9.   NSLog(@"s2");
  10. });
  11. dispatch_async(concurrencyQueue, ^{
  12.   sleep(1);
  13.   NSLog(@"s3");
  14. });
复制代码

  打印结果:
1.png

  从打印结果可以看出来,任务全在同一个线程中执行,但是并不是在主线程,而是在子线程执行。不过任务执行只有顺序地执行,任务没有执行完毕之前,下一个任务是不能开始的。

  创建并发队列

  通过dispatch_queue_create函数来创建队列,参数一是一个C语言的字符串,是队列的标签,也就是名称,通常是采用com..这样的格式。参数二是指定串行队列还是并发队列。

  • 创建串行队列传:DISPATCH_QUEUE_SERIAL(也就是NULL)
  • 创建并发队列传:DISPATCH_QUEUE_CONCURRENT

  1. dispatch_queue_tserialQueue = dispatch_queue_create("com.huangyibiao.serial-queue",
  2.                                                     DISPATCH_QUEUE_CONCURRENT);
  3. dispatch_async(serialQueue, ^{
  4.   NSLog(@"s1");
  5. });
  6. dispatch_async(serialQueue, ^{
  7.   sleep(2);
  8.   NSLog(@"s2");
  9. });
  10. dispatch_async(serialQueue, ^{
  11.   sleep(1);
  12.   NSLog(@"s3");
  13. });
复制代码

  打印结果如下:
1.png

  结尾

  本篇到此为止,量不多,应该比较好吸收。文中若有不正确之处,请在评论中指出!看到这里,对GCD中的队列知识应该已经掌握得差不多了!
原文作者:标哥 来源:推酷


相关帖子

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部