0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

为什么需要并发编程?GCD如何执行并发/并行?

Android编程精选 来源:稀土掘金 2023-07-21 10:26 次阅读

为什么需要并发

假设您在主线程上并且需要来自服务器的数据。您从服务器请求数据并等待,直到您从服务器获得响应。在此期间,您的主线程不会执行任何与 UI 相关的工作,这会使您的应用程序无响应。

假设服务器在此期间需要 10 秒才能给出响应,如果用户点击按钮,系统将不会响应它,这对用户来说非常糟糕。

如果你可以在同一时间(或大约在同一时间)运行的这两个任务,一个线程专门处理用户界面相关的工作,其他的线程处理耗时任务。这样一来,上面的情况就不会发生了。

并发

并发意味值应用程序可以使用分割时间的方式同时处理多个任务。如果一台计算机只有一个CPU,那么它无法在一个精确的时间点上同时运行多个任务,但是可以通过上下文切换的方式在一段时间(很短,比如1s)内执行多个任务。

上下文切换是指存储线程的状态,并在将来恢复这个状态继续执行。这允许多个进程共享一个CPU资源,同时这也是多任务操作系统的基本功能。

并行

并行指多个任务同时发生,并没有上下文切换。

对于我们讨论的情况,如果并行地执行网络调用,那么将有两个线程在两个不同的内核上执行主线程和后台指令,与前一个相比,速度非常快,但需要额外的物理要求-需要CPU有多核。

如下图所示,在并行的情况下,两条线程真的在同时执行;而并发,在一个线程执行时,另一个在休眠。

e2981d1e-26f1-11ee-962d-dac502259ad0.jpg

关于线程的小知识

在单核CPU上,如果你创建了10条线程,那么它只能使用并发/时间片分割/上下文切换的方式执行它们

在10核CPU上,如果你创建了10条线程,那么它们可能以下面的方式执行:

使用上下文切换的方式在1个核心上并发执行

每个线程在独立的核心上并行执行

一部分并发执行,另外一部分并行执行

在单核CPU上,如果你创建了1000条线程,那么CPU只会忙着上下文切换,而不会执行实质性的任务。可见,创建合理的线程数量也是一个不小的挑战。

GCD 如何执行并发/并行

GCD 在幕后管理共享线程池并在该池中添加最佳线程数。使用 GCD,您将代码块或工作项添加到队列中,GCD 决定在哪个线程上执行它们。GCD 根据系统物理条件或当前负载并发或并行执行此任务。

注意:如果你给 GCD 分配两个任务,你不确定它是并发还是并行运行。

从现在开始,我们将使用术语并发代表并发/并行。

使用GCD,开发者有什么责任

您所要做的就是定义要并发执行的任务并将它们添加到适当的调度队列中。GCD 负责创建所需的线程并安排您的任务在这些线程上运行,这非常酷

调度队列

调度队列是一种基于 C 的组件,用于执行自定义任务。调度队列总是按照任务添加到队列的顺序出列和启动任务。调度队列是线程安全的,这意味着您可以同时从多个线程访问它们。注意,队列不是线程!

如果您想通过 GCD 执行并发任务,请将它们添加到适当的调度队列中。GCD 将基于队列的配置,挑选并执行任务。

串行队列

串行调度队列按照添加到队列的顺序一次执行一项任务。假设您将五个任务添加到串行队列, GCD 将从第一个任务开始,在它执行完成之前,第二个任务将不会开始。

串行队列通常用于同步对特定资源的访问。假设您有两个网络调用都需要 10 秒,因此您决定将这两个任务移到某些后台线程上,而且它们都在访问相同的资源,您想要进行一些同步,您可以将这些任务放在串行队列中。

串行队列串行执行任务意味着一次只有一个线程在使用,但不能保证它们在同一线程上执行。

您可以根据需要创建任意数量的串行队列,并且每个队列相对于所有其他队列同时运行。换句话说,如果您创建四个串行队列,则每个队列一次仅执行一项任务,但最多仍可以同时执行四个任务,每个队列一个。

如果您有两个任务访问相同的共享资源,但他们在不同的线程上运行,则任一线程都可以先修改资源,您需要使用锁来确保两个任务不会同时修改该资源。您可以将两个任务添加到串行调度队列,以确保在任何给定时间只有一个任务修改共享资源。这种基于队列的同步比锁更有效,因为在有竞争和无竞争的情况下,锁总是需要一个昂贵的内核陷阱,而调度队列主要在应用程序的进程空间中工作,并且只在绝对必要时调用内核。

并发队列

并发队列并发执行一个或多个任务

如果您将四个单独的任务添加到并发队列,这些任务将按照它们添加到队列的顺序启动。GCD 选择第一个任务在一段时间内执行它,然后在不等待第一个任务完成的情况下启动第二个任务,依此类推。这是理想的地方,这不仅可以真正地做到后台执行,而且不关心这些任务是否也与其他任务同时运行

当前正在执行的任务在由调度队列管理的不同线程上运行。

在任何时间点,执行的任务数量是可变的,这取决于系统条件。当您创建具有四个任务的并发队列时,它会创建多少个线程?答案是不确定。GCD 将使用多少个线程来执行这些任务,这取决于系统条件,它有可能可以使用一条或四条线程。

在 GCD 中,有两种方法可以同时运行任务,创建自定义并发队列或使用全局并发队列。

自定义和全局并发队列的区别

如下图所示,我们创建了两个全局并发队列,您可以看到由于全局队列是整个系统共享的并发队列,因此它始终返回相同的队列;而自定义并发队列是私有的,每次创建时都会返回新队列。

e2bde26a-26f1-11ee-962d-dac502259ad0.jpg

有四个不同优先级的全局并发队列,但在设置全局并发队列时,不直接指定优先级。

相反,您指定服务质量 (QoS),其中包括用户交互、用户启动、实用程序和后台,其中用户交互具有最高优先级,而后台具有最低优先级。下面是QoS的使用建议。

.userInteractive 标志任务需要被立即执行以便提供更出色的用户体验。通常用来做UI更新,事件处理等低延时的任务。该类型的任务不应过多。

.userInitiated 标志任务被用户通过UI界面创建,但是可以被异步执行。通常用在用户一个操作后需要等待,结果返回后继续之前的操作。

.default 默认值。用于一般性异步任务。

.utility 标志任务需要较长时间,通常会关联一个进度。比如:I/O、网络请求等。

.background 标志任务的执行用户不太会关心。比如:预加载数据。

与全局队列相比,您可以使用自定义队列执行以下任务:

您可以指定一个对您有意义的标签,以便在自定义队列上进行调试

你可以暂停和重启: queue.suspend() queue.resume()

提交栅栏任务: queue.async(flags: .barrier) { ... }

主队列

主队列是一个全局可用的串行队列,它在应用程序的主线程上执行任务

该队列与应用程序的运行循环一起工作,以将排队任务和运行循环的其他事件源任务交错执行。因为它在应用程序的主线程上运行,所以主队列通常用作应用程序的关键同步点。

同步与异步

我们已经学习了如何在队列上串行或并发地执行任务。使用 GCD,您还可以同步或异步的调度队列。

一般来说,同步函数(sync)在任务完成后将控制权返回给调用者。而异步函数(async)会在函数调用后,立即将将控制权返回给调用者,它不会等等任务完成。

e2d668da-26f1-11ee-962d-dac502259ad0.jpg

如上图,您在并发全局队列上执行耗时的任务,但主线程仍然很忙,因为您在主线程 main 上同步地在分派任务,它会一直等到任务执行完成。

e2ec1824-26f1-11ee-962d-dac502259ad0.jpg

如上图:我们异步的分派任务,它立即返回到主线程,主线程将首先打印,队列上的列任务将并发执行。

预防死锁

在并发计算中,死锁是一个组的每个成员都在等待另一个成员(包括它自己)采取行动的状态

e306bb7a-26f1-11ee-962d-dac502259ad0.jpg

在上图中,queue是一个串行队列,通过async派发的任务A,通过sync派发了任务B。此时A会等待B完成后继续向下,而B在A没有完成之前是不会开始。这就造成了死锁。

e31cc564-26f1-11ee-962d-dac502259ad0.jpg

同样,上图的主队列任务A(viewDidLoad方法)使用sync派发任务B,也会造成相互等待从而死锁。

DispatchWorkItem

DispatchWorkItem是一项任务的包装器,可以多次使用,也可以取消。

letqueue=DispatchQueue(label:"com.swiftpal.dispatch.workItem")

//Createaworkitem
letworkItem=DispatchWorkItem(){
print("StoredTask")
}

//Task1
queue.async(execute:workItem)

//Task2
queue.asyncAfter(deadline:DispatchTime.now()+1,execute:workItem)

//WorkItemCancel
workItem.cancel()

//Task3
queue.async(execute:workItem)

ifitem.isCancelled{
print("Taskwascancelled")
}

这里我们创建了一个串行队列,又创建了一个DispatchWorkItem,它只包含一句代码。

接下来,我们在取消任务之前派发了该任务两次,之后再次派发该任务。但是对于输出,我们只会看到一次Stored task。






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    19178

    浏览量

    229200
  • 控制器
    +关注

    关注

    112

    文章

    16214

    浏览量

    177478
  • QoS
    QoS
    +关注

    关注

    1

    文章

    136

    浏览量

    44753
  • 调度器
    +关注

    关注

    0

    文章

    98

    浏览量

    5243

原文标题:Swift 并发编程一

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    并发并行、进程、线程和协程的区别

    希望的是能一次性预存很多批处理任务进入内存,然后通过一定的处理规则指定(作业调度算法)来让这些批处理任务划分CPU的时间,这样CPU的状态就像是第一秒执行A任务,第二秒执行B任务,这样看起来,A任务和B任务就像是同时在进行。这个模式,就叫做
    发表于 08-05 08:24

    Python中的并行性和并发性分析

      在Python编程语言当中,很多人对Python中的并行性和并发性不了解。今天我们将讨论python中的并发并行性www.zpedu.
    发表于 08-21 17:45

    Lite Actor:方舟Actor并发模型的轻量级优化

    执行的能力,如图1所示,在一个时间段中可能有多个任务都处于已启动运行到运行完毕之间,同时,并发单元也可以在多核设备下并行执行,可以极大地提高多核设备的运行性能。 图1
    发表于 07-18 12:00

    移动应用高级语言开发——并发探索

    (Actor、函数式编程),具有容错性好、特定场景性能表现很好且易于维护和测试的优势,但也存在应用场景有限、不适合细粒度并行等短板。 03►移动应用框架并发 3.1►►Dart 语言 Dart是一门新的
    发表于 08-28 17:08

    HarmonyOS如何使用异步并发能力进行开发

    并发是指异步代码在执行到一定程度后会被暂停,以便在未来某个时间点继续执行,这种情况下,同一时间只有一段代码在执行。 ● 多线程并发允许在
    发表于 09-22 17:35

    Java并发编程实战

    Java并发编程实战
    发表于 03-19 11:24 7次下载

    并行并发哪个好?并行并发的概念和区别

    摘要:并发并行是两个既相似而又不相同的概念:并发性,又称共行性,是指能处理多个同时性活动的能力;并行是指同时发生的两个并发事件,具有
    发表于 12-08 09:12 6.6w次阅读
    <b class='flag-5'>并行</b>和<b class='flag-5'>并发</b>哪个好?<b class='flag-5'>并行</b>和<b class='flag-5'>并发</b>的概念和区别

    七种常见的并发编程模型简介

    1. 线程与锁 线程与锁模型有很多众所周知的不足,但仍是其他模型的技术基础,也是很多并发软件开发的首选。 2. 函数式编程 函数式编程日渐重要的原因之一,是其对并发
    的头像 发表于 03-15 17:21 4637次阅读

    JAVA并发编程实践

    JAVA并发编程实践资料免费下载。
    发表于 06-01 15:31 15次下载

    Java并发编程的艺术

    Java并发编程的艺术说明。
    发表于 06-01 15:31 16次下载

    用于MCU上的代码下载与执行并发并行XIP闪存和SRAM设计

    电子发烧友网站提供《用于MCU上的代码下载与执行并发并行XIP闪存和SRAM设计.zip》资料免费下载
    发表于 09-05 17:14 3次下载
    用于MCU上的代码下载与<b class='flag-5'>执行</b>的<b class='flag-5'>并发</b><b class='flag-5'>并行</b>XIP闪存和SRAM设计

    NVIDIA Triton 系列文章(10):模型并发执行

    前面已经做好了每个推理模型的基础配置,基本上就能正常让 Triton 服务器使用这些独立模型进行推理。接下来的重点,就是要让设备的计算资源尽可能地充分使用,首先第一件事情就是模型并发执行
    的头像 发表于 01-05 11:55 1086次阅读

    Java并发包之CAS介绍

    首先,用1000个客户端进程来模拟并发,并使用信号量Semaphore 控制同时100个线程并发执行,采用同步器CountDownLatch 确保并发线程总数
    的头像 发表于 06-09 15:55 613次阅读
    Java<b class='flag-5'>并发</b>包之CAS介绍

    shell脚本实现并发多进程

    。 使用xargs命令:xargs命令可以从标准输入中读取数据,并将其作为参数传递给其他命令。可以将需要并发执行的命令与xargs结合使用,以实现多进程并发
    的头像 发表于 11-08 10:20 1272次阅读

    操作系统上并行并发的区别

    理解并发并行的例子 先举例子来理解这2个概念的区别。 老师让两个同学去办公室谈话。如果这两同学(进程)是并列跨过办公室门(CPU)的,那么就是并行。如果同学A先进同学B后进入(或者先B后A),或者
    的头像 发表于 11-09 14:42 1931次阅读
    操作系统上<b class='flag-5'>并行</b>和<b class='flag-5'>并发</b>的区别