Swift 6.2 可接近的并发
采用 Swift 6.2 并发模型的模式,其中代码默认在单线程上运行,并发是显式引入的。在无需牺牲性能的情况下消除常见的数据竞争错误。
何时启用
- 将 Swift 5.x 或 6.0/6.1 项目迁移到 Swift 6.2
- 解决数据竞争安全编译器错误
- 设计基于 MainActor 的应用架构
- 将 CPU 密集型工作卸载到后台线程
- 在 MainActor 隔离的类型上实现协议一致性
- 在 Xcode 26 中启用“可接近的并发”构建设置
核心问题:隐式的后台卸载
在 Swift 6.1 及更早版本中,异步函数可能会被隐式卸载到后台线程,即使在看似安全的代码中也会导致数据竞争错误:
Swift 6.2 修复了这个问题:异步函数默认保持在调用者所在的 actor 上。
核心模式 — 隔离的一致性
MainActor 类型现在可以安全地符合非隔离协议:
编译器确保该一致性仅在主 actor 上使用:
核心模式 — 全局和静态变量
使用 MainActor 保护全局/静态状态:
MainActor 默认推断模式
Swift 6.2 引入了一种模式,默认推断 MainActor — 无需手动标注:
此模式是选择启用的,推荐用于应用、脚本和其他可执行目标。
核心模式 — 使用 @concurrent 进行后台工作
当需要真正的并行性时,使用 @concurrent 显式卸载:
重要: 此示例需要启用“可接近的并发”构建设置 — SE-0466 (MainActor 默认隔离) 和 SE-0461 (默认非隔离非发送)。启用这些设置后,
extractSticker会保持在调用者所在的 actor 上,使得可变状态的访问变得安全。如果没有这些设置,此代码存在数据竞争 — 编译器会标记它。
要使用 @concurrent:
- 将包含类型标记为
nonisolated - 向函数添加
@concurrent - 如果函数还不是异步的,则添加
async - 在调用点添加
await
关键设计决策
迁移步骤
- 在 Xcode 中启用:构建设置中的 Swift Compiler > Concurrency 部分
- 在 SPM 中启用:在包清单中使用
SwiftSettingsAPI - 使用迁移工具:通过 swift.org/migration 进行自动代码更改
- 从 MainActor 默认值开始:为应用目标启用推断模式
- 在需要的地方添加
@concurrent:先进行性能分析,然后卸载热点路径 - 彻底测试:数据竞争问题会变成编译时错误
最佳实践
- 从 MainActor 开始 — 先编写单线程代码,稍后再优化
- 仅对 CPU 密集型工作使用
@concurrent— 图像处理、压缩、复杂计算 - 为主要是单线程的应用目标启用 MainActor 推断模式
- 在卸载前进行性能分析 — 使用 Instruments 查找实际的瓶颈
- 使用 MainActor 保护全局变量 — 全局/静态可变状态需要 actor 隔离
- 使用隔离的一致性,而不是
nonisolated变通方法或@Sendable包装器 - 增量迁移 — 在构建设置中一次启用一个功能
应避免的反模式
- 对每个异步函数都应用
@concurrent(大多数不需要后台执行) - 在不理解隔离的情况下使用
nonisolated来抑制编译器错误 - 当 actor 提供相同安全性时,仍保留遗留的
DispatchQueue模式 - 在并发相关的 Foundation Models 代码中跳过
model.availability检查 - 与编译器对抗 — 如果它报告数据竞争,代码就存在真正的并发问题
- 假设所有异步代码都在后台运行(Swift 6.2 默认:保持在调用者所在的 actor 上)
何时使用
- 所有新的 Swift 6.2+ 项目(“可接近的并发”是推荐的默认设置)
- 将现有应用从 Swift 5.x 或 6.0/6.1 并发迁移过来
- 在采用 Xcode 26 期间解决数据竞争安全编译器错误
- 构建以 MainActor 为中心的应用架构(大多数 UI 应用)
- 性能优化 — 将特定的繁重计算卸载到后台


