菜单

任务和异步运行时

相关源文件

本文档描述了 Swift 的任务系统和异步运行时,它们构成了 Swift 并发模型的基础。任务是 Swift 结构化并发架构的基本单元,代表了可以创建、调度、等待和取消的异步工作。有关在此基础上构建的 Actor 的信息,请参阅Actor 和隔离

任务基础

任务是 Swift 并发系统中的一个异步工作单元。每个任务都具有

  • 唯一的标识
  • 优先级级别
  • 与其他任务(父子关系)的结构化关系
  • 可取消的能力
  • 关联的执行器,决定任务的运行位置
  • 任务局部值存储

来源:[include/swift/ABI/Task.h:66-175], [include/swift/ABI/Task.h:344-536], [stdlib/public/Concurrency/Task.cpp:81-127]

任务生命周期

来源:[stdlib/public/Concurrency/Task.cpp:193-316], [stdlib/public/Concurrency/Task.swift:197-229]

任务类型与创建

Swift 支持多种类型的任务,每种任务都有不同的行为和用例。

任务类型创建方法关系继承描述
无结构化Task {}独立上下文和任务局部值在当前 Actor 的上下文中执行
分离Task.detached {}无父级完全独立的任务
子级通过任务组或 async-let有父级优先级和任务局部值结构化的子任务
组子级group.addTask {}有父任务组优先级和任务局部值任务组中的子任务
Async-letasync let x = expr有父级优先级和任务局部值Async let 的特殊子任务

每种任务类型在创建时都带有特定的标志,这些标志决定了其继承行为以及与其他任务的关系。

来源:[stdlib/public/Concurrency/Task.swift:585-815], [stdlib/public/Concurrency/Task.cpp:678-950]

任务结构和内存管理

任务在运行时由 `AsyncTask` 类表示,该类扩展了 `Job` 类。任务可能包含额外的片段,具体取决于其类型。

任务内存通过专门的分配器进行管理,该分配器可以快速分配任务特定的内存,并在任务完成后自动释放。

来源:[stdlib/public/Concurrency/Task.cpp:678-720], [include/swift/ABI/Task.h:344-536], [stdlib/public/Concurrency/Task.cpp:497-550]

执行器和任务调度

任务由执行器执行,执行器决定任务何时何地运行。Swift 有几种类型的执行器:

  1. 串行执行器:保证工作项的顺序执行
  2. 全局/通用执行器:没有特定要求的任务的默认执行器
  3. 主执行器:用于在主线程上运行任务的特殊执行器
  4. Actor 执行器:每个 Actor 都有自己的执行器来维护隔离

任务可以调度到执行器上。

执行器负责对任务进行优先级排序,并确保它们在正确的上下文中运行。优先级较高的任务可能会先于优先级较低的任务执行。

来源:[stdlib/public/Concurrency/Actor.cpp:214-361], [stdlib/public/Concurrency/Task.cpp:225-315], [stdlib/public/Concurrency/PartialAsyncTask.swift:96-154]

任务优先级

Swift 任务具有优先级系统,有助于确定执行顺序。

优先级用于

  1. 调度:优先级较高的任务可能会先于优先级较低的任务进行调度。
  2. 防止优先级反转:当低优先级任务阻塞高优先级任务时,低优先级任务可能会被暂时提升优先级。
  3. 继承:子任务继承其父任务的优先级(可能降级)。

来源:[stdlib/public/Concurrency/Task.swift:277-382], [stdlib/public/Concurrency/Task.cpp:837-910]

任务组

任务组允许管理子任务的动态集合。主要有两种类型:

  1. TaskGroup:收集并返回子任务的结果。
  2. ThrowingTaskGroup:与 TaskGroup 相同,但允许传播错误。
  3. DiscardingTaskGroup:不收集结果,适用于“即发即弃”的操作。

任务组提供以下操作:

  • 添加子任务
  • 等待下一个已完成任务的结果
  • 取消组中的所有任务
  • 检查组是否为空

来源:[stdlib/public/Concurrency/TaskGroup.swift:65-825], [stdlib/public/Concurrency/TaskGroup.cpp:156-479], [stdlib/public/Concurrency/DiscardingTaskGroup.swift:15-84]

任务取消

任务可以被取消,这意味着它们应尽快停止执行。取消是协作性的,即任务需要检查并响应取消。

取消有几个关键属性:

  • 它会自动传播到子任务。
  • 它是协作性的——任务需要检查并响应取消。
  • 可以使用 `withTaskCancellationHandler` 注册取消处理程序。
  • 被取消的任务可能会抛出 `CancellationError` 或以其他方式处理取消。

来源:[stdlib/public/Concurrency/Task.swift:197-229], [stdlib/public/Concurrency/TaskCancellation.swift:16-73]

任务局部值

任务局部值是隐式随任务携带并可被任务子任务访问的值。

任务局部值

  • 使用 `@TaskLocal` 属性包装器定义。
  • 在没有绑定值时使用默认值。
  • 可以使用 `withValue` 方法绑定到新值。
  • 会自动由子任务继承(但不会由分离的任务继承)。
  • 可以同步或异步读取。

来源:[stdlib/public/Concurrency/TaskLocal.swift:32-144], [stdlib/public/Concurrency/TaskLocal.cpp:86-200]

Future 和等待结果

Swift 异步运行时实现了一种类似 future 的模式,其中任务可以表示一个未来的值。其他任务可以使用 `await` 关键字等待此值。

关键概念:

  • 具有返回值的每个任务都实现了一个 future 机制。
  • `waitFuture` 操作会挂起当前任务,直到 future 完成。
  • 当 future 完成时,它会使用结果恢复所有等待的任务。
  • Future 的结果可以是值或错误。

来源:[stdlib/public/Concurrency/Task.cpp:114-197], [stdlib/public/Concurrency/Task.swift:155-195]

Continuations 和任务挂起

当任务等待异步操作时,它会挂起执行并创建一个 continuation,该 continuation 可用于稍后恢复任务。

Swift 提供了几种类型的 continuations:

  • `UnsafeContinuation`:基本的 continuation,没有安全检查。
  • `CheckedContinuation`:添加安全检查以检测误用。
  • 用于不同场景的内部 continuation 类型(抛出/非抛出)。

来源:[stdlib/public/Concurrency/CheckedContinuation.swift:15-90], [stdlib/public/Concurrency/Task.cpp:497-613]

实现细节

Swift 任务系统实现涉及 Swift 代码和底层运行时支持之间的复杂交互。

  1. 任务创建:任务使用运行时中的 `swift_task_create` 创建,该函数分配内存并初始化任务结构。
  2. 任务调度:任务使用作业队列调度到执行器上。
  3. 任务挂起:当任务等待时,它会捕获其 continuation 点并挂起。
  4. 任务恢复:当等待的操作完成时,任务会在 continuation 点恢复。
  5. 任务状态记录:任务维护状态记录以跟踪子任务、取消处理程序和其他信息。
  6. 任务内存管理:任务拥有自己的内存分配系统以提高效率。

该实现处理优先级继承、任务局部值传播和取消等细节,使这些功能对 Swift 开发人员来说大多是透明的。

来源:[stdlib/public/Concurrency/Task.cpp:678-950], [stdlib/public/Concurrency/TaskPrivate.h:60-109], [include/swift/Runtime/Concurrency.h:60-365]