[ PROMPT_NODE_25530 ]
swift-6-2-concurrency
[ SKILL_DOCUMENTATION ]
## Swift 6.2 中的并发编程更新
并发编程很困难,因为在多个任务之间共享内存容易出错,从而导致不可预测的行为。
## 数据竞争安全性
Swift 6 中的数据竞争安全性在编译时防止了这些错误,因此您可以编写并发代码,而不必担心引入难以调试的运行时错误。但在许多情况下,最自然的编码方式容易导致数据竞争,从而导致必须解决的编译器错误。一个具有可变状态的类,例如这个 `PhotoProcessor` 类,只要您不并发访问它,就是安全的。
swift
class PhotoProcessor {
func extractSticker(data: Data, with id: String?) async -> Sticker? { }
}
@MainActor
final class StickerModel {
let photoProcessor = PhotoProcessor()
func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? {
guard let data = try await item.loadTransferable(type: Data.self) else {
return nil
}
// 错误:发送 'self.photoProcessor' 存在导致数据竞争的风险
// 将主 Actor 隔离的 'self.photoProcessor' 发送到非隔离的实例方法 'extractSticker(data:with:)'
// 存在导致非隔离使用和主 Actor 隔离使用之间数据竞争的风险
return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier)
}
}
它有一个异步方法,通过计算给定图像数据的主题来提取 `Sticker`。但如果您尝试从主 Actor 上的 UI 代码调用 `extractSticker`,您会收到一个错误,提示该调用存在导致数据竞争的风险。这是因为语言中有几个地方隐式地将工作卸载到后台,即使您从未需要代码并行运行。
Swift 6.2 改变了这种理念,默认保持单线程,直到您选择引入并发。
swift
class PhotoProcessor {
func extractSticker(data: Data, with id: String?) async -> Sticker? { }
}
@MainActor
final class StickerModel {
let photoProcessor = PhotoProcessor()
func extractSticker(_ item: PhotosPickerItem) async throws -> Sticker? {
guard let data = try await item.loadTransferable(type: Data.self) else {
return nil
}
// 由于易用并发和默认 Actor 隔离,在 Swift 6.2 中不再是数据竞争错误
return await photoProcessor.extractSticker(data: data, with: item.itemIdentifier)
}
}
Swift 6.2 中的语言更改使最自然的编码方式变得无数据竞争。