Swift 中 Sendable 的使用
在 Swift 中,Sendable
是一种协议,用于标记类型是否可以安全地跨线程传递。这是 Swift 并发模型(从 Swift 5.5 引入)的一部分,主要用于确保并发环境中数据传递的安全性。
Sendable
的概念
Sendable
表示一个类型的实例可以安全地从一个线程传递到另一个线程。- 它是一个 marker protocol(标记协议),即协议本身没有要求实现任何方法或属性。
- 许多标准库类型(如
Int
、String
、Array
)已经默认符合Sendable
。
在使用并发功能(如 Task
、Actor
)时,编译器会检查类型是否遵循 Sendable
,以确保数据传递的线程安全性。
为什么需要 Sendable
在多线程环境中,某些类型可能会因为并发访问而导致数据竞争或未定义行为。Sendable
提供了一个静态安全机制,帮助开发者提前捕获潜在问题。
例如:
- 值类型(如
struct
)可以跨线程传递,因为它们是不可变的或每个线程有独立的副本。 - 引用类型(如
class
)可能在多线程访问时引发问题,需要特殊处理。
Sendable
的自动符合
值类型
- 如果一个值类型的所有成员类型都符合
Sendable
,该值类型自动符合Sendable
。
struct MyStruct: Sendable {
var value: Int // Int 是 Sendable
}
引用类型
- 类默认不符合
Sendable
,因为它们可能会在并发环境中引发数据竞争。 - 需要显式声明为
Sendable
并确保其线程安全性。
final class MyClass: Sendable {
let value: Int // 只读属性是线程安全的
}
自定义类型实现 Sendable
如果类型的线程安全性不能由编译器自动推断,开发者可以通过显式声明遵守 Sendable
,并使用 @unchecked
关键字告诉编译器我们确认其是线程安全的。
示例:显式声明 Sendable
final class CustomClass: @unchecked Sendable {
let value: Int
init(value: Int) {
self.value = value
}
}
- 使用
@unchecked
表示开发者自己保证线程安全,编译器不再检查。
Sendable
的使用场景
在并发任务中传递数据
当在并发任务中使用共享数据时,Sendable
可确保数据传递是安全的。
struct User: Sendable {
let name: String
let age: Int
}
func fetchUserData() async -> User {
return User(name: "Alice", age: 25)
}
Task {
let user = await fetchUserData()
print("User: \(user)")
}
与 Actor 配合
Actor 的隔离模型依赖于 Sendable
,只有符合 Sendable
的类型才能在 Actor 间安全传递。
actor UserManager {
func updateUser(name: String) -> String {
return "Updated \(name)"
}
}
let manager = UserManager()
Task {
let result = await manager.updateUser(name: "Alice")
print(result)
}
标准库中符合 Sendable
的类型
以下类型默认符合 Sendable
:
- 值类型:
Int
、String
、Array
、Dictionary
、Set
等。 - 一些引用类型:
URL
、UUID
等。
编译器检查
如果在并发代码中使用不符合 Sendable
的类型,编译器会报错。例如:
class NonSendableClass {
var value = 0
}
func performTask(data: NonSendableClass) async {
// 编译器报错:NonSendableClass does not conform to Sendable
}
let data = NonSendableClass()
Task {
await performTask(data: data)
}
注意事项
- 引用类型线程安全性:对引用类型使用
@unchecked Sendable
时需确保其内部状态是线程安全的。 - 可变属性:在符合
Sendable
的类型中,使用let
限制属性为不可变。 - 静态分析:Swift 编译器在异步和并发环境中会自动检查类型是否符合
Sendable
。
总结
Sendable
是 Swift 并发模型的重要组成部分,确保类型可以安全地在线程间传递。- 值类型通常自动符合
Sendable
,引用类型需要开发者手动声明或确保线程安全。 - 使用
Sendable
的检查可以帮助捕获并发中的潜在问题,是编写健壮代码的一个重要工具。