Swift 5.10 现已发布,此版本在并发语言模型中实现了完全的数据隔离。公告称,“这一重要的里程碑经过了多年的积极开发,历经多个版本。”
并发模型是在 Swift 5.5 中引入的,包括async
/await
、actors 和结构化并发 (structured concurrency)。Swift 5.7 引入了Sendable
线程安全类型的基本概念,其值可以在任意并发上下文之间共享,而不会引入数据竞争的风险。现在,在 Swift 5.10 中,当启用完整的并发检查选项时,语言的所有区域都会在编译时强制执行完全数据隔离。
Swift 5.10 中的完全数据隔离为下一个主要版本 Swift 6 奠定了基础。Swift 6.0 编译器将提供新的、可选的 Swift 6 语言模式,该模式将默认强制执行完全数据隔离,项目团队将着手进行过渡消除所有用 Swift 编写的软件之间的数据竞争。
Swift 5.10 会在某些情况下产生数据竞争警告,而在这些情况下,通过额外的编译器分析可以证明代码是安全的。Swift 6 版本的语言开发的一个主要重点是通过减少已证明安全的常见代码模式中的误报并发错误,来提高严格并发检查的可用性。
完全数据隔离
Swift 5.10 完善了语言各个角落的数据竞争安全语义,并修复了Sendable
和 actor isolation checking 中的大量错误,以加强完整并发检查的保证。使用编译器 flag-strict-concurrency=complete
构建代码时,Swift 5.10 将在编译时诊断数据竞争的可能性,除非使用 explicit unsafe opt-out(例如nonisolated(unsafe)
或@unchecked Sendable
)。
warning: expression is 'async' but is not marked with 'await'
let model = MyModel.shared
^~~~~~~~~~~~~~
await
解决数据竞争的可能修复方法有:
1) access MyModel.shared
asynchronously using await
2) 使MyModel.init
和MyModel.shared
两者都nonisolated
,并将需要 main actor 的代码移到单独的隔离方法中,或
3) 将useShared()
隔离到@MainActor
。
可以在 Swift 5.10 发行说明中查看更多详细信息。
Unsafe opt-outs
Swift 5.10 引入了一个新nonisolated(unsafe)
keyword,用于 opt out 对存储的属性和变量的 actor isolation checking。nonisolated(unsafe)
可用于任何形式的存储,包括存储属性、局部变量和全局/静态变量。
nonisolated(unsafe)
还消除了对@unchecked Sendable
wrapper types 的需要,这些类型仅用于在不存在并发访问可能性时跨隔离边界传递非Sendable
值的特定实例:
// 'MutableData' is not 'Sendable'
class MutableData { ... }
func processData(_: MutableData) async { ... }
@MainActor func send() async {
nonisolated(unsafe) let data = MutableData()
await processData(data)
}
Swift 6 之前的语言演变
Swift 的下一个版本将是 Swift 6。鉴于 Swift 5.10 中的完整并发模型限制过多,团队目前正在积极开发几项 Swift Evolution 提议,以通过消除误报数据竞争错误来提高完整数据隔离的可用性。
这项工作包括:当编译器确定没有并发访问的可能性时,取消对跨隔离边界传递 non-Sendable
值的限制;为 functions 和 key-paths 提供更有效的Sendable
inference 等。可以在 Swift.org/swift-evolution 上找到将完善 Swift 6 的提案集。
更多详情可查看官方博客。