Swift 中 Actor 的使用
在 Swift 中,Actor 是一种新的并发模型(从 Swift 5.5 引入),用于在多线程环境中提供线程安全的状态管理。它是对传统类的一种扩展,通过将状态隔离到单个线程来防止数据竞争和同步问题。
Actor 的主要特点
- 状态隔离:Actor 内的属性和方法是线程安全的,同一时间只能有一个任务访问其内部状态。
- 异步访问:外部访问 Actor 的属性或方法时需要使用
await
。 - 可重入:Actor 默认是可重入的,允许其他任务在当前任务挂起时执行。
定义与使用 Actor
定义 Actor
Actor 的定义类似于类,但使用关键字 actor
。
actor Counter {
private var count = 0
func increment() {
count += 1
}
func getCount() -> Int {
return count
}
}
使用 Actor
由于 Actor 的状态是隔离的,外部访问其方法或属性时需要使用 await
。
let counter = Counter()
Task {
await counter.increment()
let currentCount = await counter.getCount()
print("Count: \(currentCount)")
}
Actor 的核心特性与规则
1. 线程安全
Actor 确保内部状态的修改是线程安全的,无需使用锁(Lock
或 DispatchQueue
)。
actor SafeCounter {
private var value = 0
func increment() {
value += 1
}
func getValue() -> Int {
return value
}
}
let safeCounter = SafeCounter()
Task {
await safeCounter.increment()
}
2. 外部访问需要异步
Actor 的方法和属性在外部访问时需要通过 await
。
actor BankAccount {
private var balance: Double = 0.0
func deposit(amount: Double) {
balance += amount
}
func getBalance() -> Double {
return balance
}
}
let account = BankAccount()
Task {
await account.deposit(amount: 100.0)
print("Balance: \(await account.getBalance())")
}
3. 可重入性
Actor 默认是可重入的,意味着当任务挂起时,其他任务可以访问 Actor 的方法或属性。
actor ReentrantActor {
func task1() async {
print("Start Task 1")
try await Task.sleep(nanoseconds: 1_000_000_000) // 模拟异步挂起
print("End Task 1")
}
func task2() {
print("Task 2 executed")
}
}
let actor = ReentrantActor()
Task {
await actor.task1()
}
Task {
await actor.task2() // 不会被阻塞
}
Actor 的使用场景
- 共享资源管理:如计数器、缓存、用户状态等需要线程安全的全局资源。
- 异步任务协调:在高并发环境中,Actor 可以用于协调多个异步任务的顺序和状态。
- 简化并发代码:替代传统的锁或串行队列,实现线程安全。
Actor 与类的对比
特性 | Actor | 类 |
---|---|---|
线程安全性 | 默认线程安全,防止数据竞争 | 不提供内置线程安全,需手动管理 |
状态访问 | 异步(await ) |
同步 |
可重入性 | 默认可重入 | 不可重入 |
用途 | 并发安全的状态管理 | 通用用途 |
与 Global Actor 的结合
Swift 提供了 Global Actor,如 @MainActor
,用于指定 Actor 的全局作用域,例如保证某些代码在主线程上执行。
@MainActor
class ViewModel {
var title: String = "Hello"
func updateTitle(to newTitle: String) {
title = newTitle
}
}
在使用时,系统会确保 ViewModel
的所有方法和属性都在主线程上执行。
注意事项
- 性能:Actor 是轻量级的,但过度使用可能影响性能。
- 数据共享:避免直接通过外部访问 Actor 的状态,应通过方法和封装访问。
- 可重入性问题:可重入 Actor 在某些情况下可能导致状态中断,需要仔细设计任务流。
总结
Actor 提供了一种现代化的并发编程模型,通过状态隔离和异步访问,简化了线程安全的实现,适用于高并发环境中的共享状态管理。结合 @MainActor
等特性,还能很好地解决主线程上的并发问题。