Tag: 并行编程

Swift并行编程—第1/4部分

并发,并行和调度队列 每当我们听到并行编程时,就会想到两个令人困惑的术语:并发和并行。 首先让我们看看现实生活中的角色: 并发性:我们的日常工作涉及多任务处理。 很多时候,我们执行多任务处理,但最终会同时完成一个任务,但是理想情况下,这就是上下文切换。 它也有一些限制。 假设我们每天有100项工作,但不能将其增加到1000项。 并行性:如果我们可以得到更多的物理东西,那么可以同时完成两个或更多的工作。 如果我有4臂,那么这篇文章可以在一半的时间内完成。 让我们来看看计算机世界中的两个术语: 并发: 并发意味着应用程序同时(并发)在一项以上的任务上取得进展。 如果计算机只有一个CPU,则该应用程序可能无法完全同时执行一项以上的任务,但是一次要在应用程序内部处理一项以上的任务。 在开始下一项任务之前,它并没有完全完成一项任务。 当我们谈论至少两个或更多任务时,并发本质上是适用的。 当一个应用程序几乎可以同时执行两个任务时,我们称其为并发应用程序。 尽管这里的任务看起来像是同时运行的,但实际上它们可能并非如此。 它们利用了操作系统的CPU时间分片功能,其中每个任务运行其任务的一部分,然后进入等待状态。 当第一个任务处于等待状态时,CPU被分配第二个任务以完成其部分任务。 操作系统根据任务的优先级工作,因此分配CPU和其他计算资源,例如内存; 依次处理所有任务,并给他们完成任务的机会。 对于最终用户,似乎所有任务都是并行运行的。 并发复杂度 假设有5个朋友搬进了房子,每个人都有一张床。 哪种更复杂的方式来构造它? 5人同时组装一张床或 每个人组装自己的床 想一想如何为几个朋友编写有关如何将床组装在一起的说明,而无需彼此扶持或等待工具。 他们需要在正确的时间协调动作,以将床的各个部分组装成成品床。 这些指令真的很复杂,很难编写,也可能很难阅读。 每个人都自己建造床时,说明非常简单,无需等待其他人完成操作或使用工具即可。 罗伯·派克 ( Rob Pike)有一个关于 并发不是并行的演讲。 平行性 并行不需要两个任务存在。 通过为每个任务或子任务分配一个内核,它可以使用CPU的多核基础结构同时运行部分任务或多个任务。 并行性本质上要求具有多个处理单元的硬件。 在单核CPU中,您可能会获得并发性,但不能获得并行性。 并发是独立执行的进程的组成,而并行性是计算的同时执行。 并行性是指应用程序将其任务分解为较小的子任务,这些子任务可以并行处理,例如在多个CPU上同时进行。 并发是一次处理很多事情,更多的是关注结构。 并行性是一次执行很多事情,其重点是执行。 一个应用程序可以是并发的,但不能是并行的,这意味着它可以同时处理一个以上的任务,但是两个任务不能同时执行。 一个应用程序可以是并行的,但不能是并行的,这意味着它可以同时处理多核CPU中一个任务的多个子任务。 应用程序既不能是并行的,也不能是并发的,这意味着它一次顺序地处理所有任务。 一个应用程序可以是并行的,也可以是并发的,这意味着它可以同时在多核CPU中同时处理多个任务。 自从出现以来,CPU技术的最大改进之一就是能够包含多个内核,因此可以运行多个线程,这意味着在任何给定时刻可以执行多个任务。 在iOS中,有两种实现并发的方法:Grand Central Dispatch和OperationQueue。 这两个主题都很广泛,因此我将本文分为四个部分 : […]

Swift并行编程—第3/4部分

本文是Swift系列并行编程的第3部分。 在第1部分中,我们研究了Dispatch Queue和系统提供的队列。 在第2部分中,我们重点介绍了定义任务和GCD提供的强大API的另一种方法。 在这篇文章中,让我们看一下Operation API和与Grand Central Dispatch相比提供的灵活性。 如果要查看系列的所有部分: 并发和GCD — Swift并行编程— 1/4 GCD —使用Swift进行并行编程—第2/4部分 操作和操作队列概述—使用Swift并行编程—第3/4部分 操作是一种面向对象的方式,用于封装需要异步执行的工作。 Operation代表单个工作单元。 它是一个抽象类,提供了一个有用的,线程安全的结构,用于对状态,优先级,依赖关系和管理进行建模。 — NSHipster 由于操作是抽象类,因此您不能直接使用它。 Foundation提供了两个系统定义的子类InvocationOperation和BlockOperation来执行任务。 就像在定义的子类中所说的那样,您只需要关注任务的实际实现即可。 一个操作只执行一次任务,因此不能再次执行它。 您可以通过将操作添加到操作队列中来执行操作。 操作队列可以通过在辅助线程上运行它们来直接执行其操作,也可以使用libdispatch库(即Grand Central Dispatch)间接地执行其操作。 因此, Operation API是Grand Central Dispatch的更高级别的抽象。 您可能想知道:什么任务? 🤔 让我们讨论以下术语: 任务 :需要完成的一项工作。 进程 :可执行代码块,可以由多个线程组成。 流程是您的应用程序的实例。 每当您执行应用程序的冷启动时,Process ID都会获得更改,而在您执行热启动时,它保持不变。 它包含执行应用程序所需的所有内容,其中包括堆栈,堆和所有其他资源。 线程 :操作系统提供的一种机制,它允许多个指令集在单个应用程序中同时运行。 与进程相比,线程与其父进程共享其内存。 这可能会导致出现问题,例如让两个线程同时更改资源(例如,变量)。 线程是iOS上的有限资源。 一个进程最多只能同时有64个线程,而在任何文档中都没有正式提及,因为它会根据上下文和内核数量而有所不同。 操作状态: 操作对象在内部维护状态,以确定何时可以安全执行,并在操作的整个生命周期内将进度通知给外部客户。 isReady:在准备好执行操作时通知客户端。 当操作准备好立即执行时,此键路径返回true […]

Swift并行编程—第2/4部分

目标队列,调度组,屏障,工作项,信号量和调度源 本文是Swift并行编程的第2部分。 与第1部分一样,我们研究了Dispatch Queue和系统提供的队列。 在本文中,我将重点介绍另一种定义任务和GCD提供的强大API的方法。 如果要查看系列的所有部分: 并发和GCD — Swift并行编程— 1/4 GCD —使用Swift进行并行编程—第2/4部分 议程: 目标队列 调度组 DispatchWorkItem 派遣壁垒 DispatchSemaphore 派遣源 1.目标队列 定制调度队列不执行任何工作,它只是将工作传递给目标队列。 默认情况下,自定义调度队列的目标队列是默认优先级的全局队列。 从Swift 3开始,一旦调度队列被激活,就无法再对其进行更改。 可以通过setTarget(queue:)函数设置自定义队列的目标队列。 在激活的队列上设置目标将进行编译,但随后会在运行时引发错误。 幸运的是,DispatchQueue初始化程序接受其他参数。 如果出于某种原因仍然需要将目标设置在已创建的队列上,则可以使用iOS 10以来可用的initiallyInactive属性来实现。 DispatchQueue(标签:“队列”,属性:.initiallyInactive) 这将允许您修改它,直到激活它。 DispatchQueue类的activate()方法将使任务执行。 由于队列尚未被标记为并发队列,因此它们将以串行顺序运行。 为了使队列并发,我们需要指定: DispatchQueue(标签:“队列”,属性:[。initiallyInactive,.concurrent]) 您可以将任何其他调度队列(甚至是另一个自定义队列)传递给目标队列,只要您从未创建周期即可。 通过简单地将自定义队列的目标队列设置为其他全局队列,可以使用该功能设置自定义队列的优先级。 只有全局并发队列和主队列才能执行块。 所有其他队列必须(最终)以这些特殊队列之一为目标。 您可能已经在使用的Dispatch API或框架中注意到了目标队列。 我在RxSwift库中发现了目标队列的使用。 使用此实现,由于任务正在异步执行,因此很难在完成时获得通知。 这是DispatchGroup图片: DispatchGroup允许工作的聚合同步。 它可以用于提交多个不同的工作项或块,并跟踪它们何时全部完成,即使它们可能在不同的队列中运行。 唯一必要的事情是在调度组上均衡地调用enter()和leave() ,以使其同步我们的任务。 调用enter()以手动通知组任务已开始,并leave以通知工作已完成。 您也可以调用group.wait() ,它会阻塞当前线程,直到该组的任务完成为止。有两种方法来调用完成块: 使用wait()然后在主队列上执行完成块 呼叫组notify() wait(timeout:) 这将阻止当前线程,但是在指定的超时后,无论如何仍将继续。 […]