Swift 6.2 Approachable Concurrency:迁移时真正改变了什么
Swift 6.2 正式引入的 Approachable Concurrency 不是关闭数据竞争检查,也不是让所有代码自动进入主线程。它调整了项目可以选择的默认值,让以 UI 为中心的模块减少不必要的隔离标注,同时用 @concurrent 明确指出确实应在并发执行器上运行的工作。迁移重点从“先给所有类型证明 Sendable”转向“先说清每段代码由谁隔离”。
默认主 actor 隔离是模块决策
启用默认 actor isolation 后,没有显式隔离的声明可以默认属于 MainActor。这对主要操作 UI 状态的应用 target 很自然:视图模型、导航状态和控制器不再需要重复写相同注解。但网络模型、算法包和服务器模块并不一定应该采用这个默认值。
不要在工作区根部一次开启后修所有错误。先按 target 盘点:这个模块的大多数可变状态是否真的由主 actor 所有?公共库是否会被后台任务和非 Apple 平台使用?测试 target 是否依赖同步构造?把选择记录在构建设置与架构文档中,避免开发者只看到神秘的诊断变化。
@Observable
final class SearchModel {
var query = ""
var results: [Result] = []
func update(using service: SearchService) async throws {
results = try await service.search(query)
}
}
在默认主 actor 隔离的应用模块中,这类 UI 模型获得符合用途的隔离。SearchService 则应该定义自己的边界:不可变且可发送的请求/响应值,actor 管理的共享缓存,或明确的并发函数。默认值减少样板代码,但没有替代设计。
async 不再等同于自动后台执行
Swift 6.2 的迁移模型让非隔离 async 函数更自然地继承调用者的上下文。仅添加 async 不表示 CPU 工作会离开当前 actor。这修正了一种危险直觉:把图像处理函数改成 async,然后以为主线程卡顿会自动消失。
确实需要并行执行、并且其参数与结果能安全跨边界的函数,可以用 @concurrent 表达意图:
@concurrent
func buildSearchIndex(from documents: [Document]) async -> SearchIndex {
var builder = SearchIndex.Builder()
for document in documents {
builder.add(document)
}
return builder.finish()
}
这不是性能装饰器。调用前应确认数据可以安全传递、函数不触碰主 actor 状态,并用 Instruments 证明工作量足以承担调度成本。小型字符串拼接没有必要为了“看起来并发”而跨执行器。
从边界开始迁移
第一步升级工具链但保留现有语言模式,建立干净基线。第二步启用诊断并按模块分类:真正共享的可变状态、只在 UI 使用的状态、跨边界的不可变值,以及不应被跨域捕获的引用。第三步先修公共边界和任务生命周期,再处理局部标注。最后才在适合的 target 打开新默认值。
不要用大量 @unchecked Sendable 清空错误列表。它把证明责任交给开发者,却没有提供锁、actor 或不可变性。每一个 unchecked 声明都应写明不变量并有并发测试。也不要到处添加 Task { @MainActor in ... };这可能隐藏上游所有权不清,并让耗时工作悄悄排在 UI actor 上。
测试行为而非只求编译通过
迁移测试应包含快速连续输入、任务取消、视图消失、错误重试和多个请求返回顺序不同。Thread Sanitizer 与严格并发诊断覆盖不同问题,二者都不能证明所有逻辑顺序正确。对于 actor 缓存,测试重复键是否合并;对于 UI 模型,测试过期响应不会覆盖新查询;对于 @concurrent 工作,确认取消和结果回到 UI 的边界明确。
性能基线也要保留。隔离修改可能减少跳转,也可能把工作搬到主 actor。记录交互延迟、主要任务时间与能耗,而不是把“警告变少”当成迁移完成。
结论
Approachable Concurrency 的真正变化是更好的默认表达:UI 模块可以默认主 actor,普通 async 可以保持调用者上下文,需要并发执行的函数用 @concurrent 明示。它降低了入口摩擦,却没有降低数据竞争标准。按 target 选择默认值、从所有权边界迁移、谨慎使用跨域豁免并验证取消与性能,才能让 Swift 6.2 的便利建立在清楚模型上。