一句话核心
Actor 通过将其状态完全隔离在单一执行上下文(executor)内,只允许通过异步消息(async 方法)访问,从而保证数据安全,不需要显式锁。
1️⃣ Actor 的基本概念
actor BankAccount {
private var balance: Int = 0
func deposit(_ amount: Int) {
balance += amount
}
func withdraw(_ amount: Int) -> Bool {
if balance >= amount {
balance -= amount
return true
} else {
return false
}
}
func getBalance() -> Int {
balance
}
}
特点:
-
状态隔离
balance只能被 actor 自己访问
-
异步访问
- 跨 actor 调用必须
await
- 跨 actor 调用必须
-
executor 单线程保证
- actor 内部执行上下文串行化
2️⃣ 数据隔离如何实现
执行上下文(executor)
- 每个 actor 有自己的 executor
- actor 内部任务顺序执行
- 同一时间只有一个任务能访问 actor 的状态
Actor (executor)
├─ Task 1 accessing balance
├─ Task 2 queued
└─ Task 3 queued
- Task 2/3 等待 Task 1 完成
- 不会出现数据竞争
- 不需要锁
async 消息传递
await account.deposit(100)
- 调用会被封装成 消息任务
- 放入 actor 的 executor 队列
- 异步顺序执行
- 任何跨 actor 访问都通过 await 调度
3️⃣ 与传统锁机制对比
| 特性 | Actor | 锁(Mutex / NSLock) |
|---|---|---|
| 数据隔离 | ✅ 完全隔离 | ❌ 手动保护 |
| 锁粒度 | 单个 actor | 任意共享资源 |
| 死锁风险 | ❌ 消息队列顺序执行 | ✅ 高(容易死锁) |
| 并发可推理性 | 高 | 低(必须仔细分析临界区) |
| 可组合性 | ✅ async/await 支持跨 actor | ❌ 复杂,需要手动管理 |
| 可扩展性 | 高(多 actor 并发) | 受锁冲突限制 |
4️⃣ Actor 的核心优势
-
消除数据竞争
- 不需要手动加锁,状态隔离 + executor 串行执行
-
消除死锁 / 优先级反转问题
- 内部消息队列顺序处理
-
与 async/await 天然整合
- 跨 actor 调用是异步的 → 自然等待
-
可组合性强
- Actor 之间可以同时处理多个任务(不同 executor)
5️⃣ 小陷阱(必须知道)
-
跨 actor 调用必须 await
await account.deposit(100) // 必须 await- 否则编译错误
-
actor 内部同步访问安全
func transfer(to other: BankAccount, amount: Int) async { if await withdraw(amount) { await other.deposit(amount) } }- 跨 actor 可能需要处理死锁或顺序问题
- 但 actor 内状态是安全的
6️⃣ 直观类比
- Actor = “单线程服务 + 异步消息队列”
- 锁机制 = “共享房间,谁先锁谁进房间”
- Actor 不用抢房间,状态独占;锁机制需要你自己管理房间的开关和优先级。
7️⃣ 面试必背总结
Swift 的 Actor 通过 executor 串行化其内部状态访问、隔离数据,只能通过异步方法访问,从而消除了数据竞争和死锁风险;相比传统锁机制,Actor 提供了更安全、更可推理、更易组合的并发模型。