专栏首页搜狗测试iOS多线程:GCD使用介绍

iOS多线程:GCD使用介绍

背景

最近作者在进行多线程问题排查和整理时,发现了好多问题都是由于GCD的使用不规范造成的,因此在这里主要分享GCD的使用方法,希望大家能够在测试时更早发现问题。

GCD简介

GCD 为苹果推出的多核编程解决方案,它不仅能够自动利用多个核心处理数据,还能够自动管理生命周期,不需要程序猿手动管理。在日常的编程中十分常用。其优点如下:

  • GCD 可用于多核的并行运算;
  • GCD 会自动利用更多的 CPU 内核(比如双核、四核);
  • GCD 会自动管理线程的生命周期(创建线程、调度任务、销毁线程);
  • 程序员只需要告诉 GCD 想要执行什么任务,不需要编写任何线程管理代码。

GCD 任务和队列

学习 GCD 之前,先来了解 GCD 中两个核心概念:『任务』 和 『队列』。

任务:就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在 GCD 中是放在 block 中的。执行任务有两种方式:『同步执行』 和 『异步执行』。两者的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力。

  • 同步执行(sync):
    • 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。
    • 只能在当前线程中执行任务,不具备开启新线程的能力。
  • 异步执行(async):
    • 异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。
    • 可以在新的线程中执行任务,具备开启新线程的能力。

队列(Dispatch Queue):这里的队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用 FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务。队列的结构可参考下图:

在 GCD 中有两种队列:『串行队列』『并发队列』。两者都符合 FIFO(先进先出)的原则。两者的主要区别是:执行顺序不同,以及开启线程数不同。

  • 串行队列(Serial Dispatch Queue)
    • 每次只有一个任务被执行。让任务一个接着一个地执行。(只开启一个线程,一个任务执行完毕后,再执行下一个任务)
  • 并发队列(Concurrent Dispatch Queue)
    • 可以让多个任务并发(同时)执行。(可以开启多个线程,并且同时执行任务)

两者具体区别如下两图所示:

GCD 的使用步骤

GCD 的使用步骤其实很简单,只有两步:

  1. 创建一个队列(串行队列或并发队列);
  2. 将任务追加到任务的等待队列中,然后系统就会根据任务类型执行任务(同步执行或异步执行)。

下边来看看队列的创建方法 / 获取方法,以及任务的创建方法。

1. 创建队列

可以使用 dispatch_queue_create 方法来创建队列。该方法需要传入两个参数:

  • 第一个参数表示队列的唯一标识符,用于 DEBUG,可为空。队列的名称推荐使用应用程序 ID 这种逆序全程域名。
  • 第二个参数用来识别是串行队列还是并发队列。DISPATCH_QUEUE_SERIAL 表示串行队列,DISPATCH_QUEUE_CONCURRENT 表示并发队列。
// 串行队列的创建方法

2. 任务的创建方法

GCD 提供了同步执行任务的创建方法 dispatch_sync 和异步执行任务创建方法 dispatch_async

// 同步执行任务创建方法
dispatch_sync(queue, ^{
    // 这里放同步执行任务代码
});
// 异步执行任务创建方法
dispatch_async(queue, ^{
    // 这里放异步执行任务代码
});

虽然使用 GCD 只需两步,但是既然我们有两种队列(串行队列 / 并发队列),两种任务执行方式(同步执行 / 异步执行),如果当前代码默认放在主队列中,我们也有两种特殊的组合方式。于是我们就有了六种不同的组合方式。这四种不同的组合方式是:

同步执行 + 并发队列 异步执行 + 并发队列 同步执行 + 串行队列 异步执行 + 串行队列 同步执行 + 主队列 异步执行 + 主队列

我们先来考虑最基本的使用,也就是当前线程为 『主线程』 的环境下,『不同队列』+『不同任务』 简单组合使用的不同区别。暂时不考虑 『队列中嵌套队列』 的这种复杂情况。

『主线程』中,『不同队列』+『不同任务』简单组合的区别:

任务

并发队列

串行队列

主队列

同步(sync)

没有开启新线程,串行执行任务

没有开启新线程,串行执行任务

死锁卡住不执行

异步(async)

有开启新线程,串行执行任务

有开启新线程(1条),串行执行任务

没有开启新线程,串行执行任务

总结

GCD的使用看起来非常简单,但是在实际使用当中必须要严格遵循队列和任务的关系,以及内部数据的线程安全,防止出现概率崩溃及锁死的情况。GCD虽然非常好用,但也意味着其产生问题时会造成更大的影响,希望大家在测试过程中重点关注。






本文分享自微信公众号 - 搜狗测试(SogouQA),作者:小K

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android APP测试之Monkey

    在Monkey测试过程中可能会出现程序崩溃(CRASH)和程序无响应的情况(ANR),要将测试的log信息获取到,从而解决bug。

    用户5521279
  • 如何做Git项目的持续集成

    持续集成(简称CI)指的是在代码提交的过程中持续地进行代码的集成、构建和自动化测试;借助CI工具,可以在代码提交的过程中通过单元测试等方式尽早地发现引入的问题。...

    用户5521279
  • 手机输入法多支线管理介绍

    问题汇总为两个大的维度: ①项目流程有不规范的地方,存在内耗,导致时间和人员浪费; ②整体项目流程确实存在不灵活,不能满足需求、版本快速迭代、临时变更的痛点。

    用户5521279
  • 扎克伯格为提高员工工作效率,亲自做了这 26 张 PPT ,值得收藏

    源 / Facebook 全球最年轻亿万富豪宝座的Facebook创始人马克·扎克伯格,为了提升员工的工作效率,亲自做了这26张PPT。 本文分享了来自Face...

    顶级程序员
  • 使用JavaScript创建队列结构

    队列和栈是两种相似的结构,区别主要在于栈是先进后出,队列是先进先出(FIFO)。队列插入元素是在队尾插入,在队列头弹出,形象的描述为排队,先到的先办事,后到的后...

    无邪Z
  • 深入理解事件循环

    本篇博客讲的东西偏底层,较难理解。虽然有的地方不够精准和全面,但是我觉得对于理解js中的异步来说已经够了,所以没有再深究一些概念(比如浏览器在这个过程中充当的角...

    Chor
  • 浅谈JS线程

    线程,对于后端的人来讲是很熟悉的,对于前端,却基本不会注意到。我们都知道JavaScript是单线程的,也就是说,同一个时间只能做一件事。说是为了避免复杂性,所...

    wade
  • Java魔法堂:找外援的利器——Runtime.exec详解

    一、前言                                  Java虽然五脏俱全但总有软肋,譬如获取CPU等硬件信息,当然我们可以通过JNI调用...

    ^_^肥仔John
  • 在小程序中实现 Mixins 方案

    在原生开发小程序的过程中,发现有多个页面都使用了几乎完全一样的逻辑。由于小程序官方并没有提供 Mixins 这种代码复用机制,所以只能采用非常不优雅的复制粘贴的...

    Fundebug
  • Golang 的 协程调度机制 与 GOMAXPROCS 性能调优

    正确地认识 G , M , P 三者的关系,能够对协程的调度机制有更深入的理解! 本文将会完整介绍完 go 协程的调度机制,包含:

    _simple

扫码关注云+社区

领取腾讯云代金券