0Pricing
Swift Academy · 课时

Actor 隔离与 nonisolated

分析隔离边界。

Actor 隔离与 nonisolated 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 4 节课。

什么是参与者隔离

参与者隔离意味着参与者的可变状态只能由运行在该参与者上的代码访问。

运行时会将访问串行化,因此两个任务永远不会同时修改该状态,从而消除数据竞争。

actor Counter {
    private var value = 0
    func increment() { value += 1 }
}

调用参与者

从参与者外部访问隔离成员时,该访问是异步的。您必须使用 await,因为调用可能会挂起,直到参与者空闲。

let counter = Counter()
func useCounter() async {
    await counter.increment()
}

参与者内部:同步访问

在参与者自己的方法中,您已经处于隔离状态,因此可以同步访问状态——对 self 无需使用 await。

actor Counter {
    private var value = 0
    func incrementTwice() {
        value += 1 // synchronous: already isolated
        value += 1
    }
}

非隔离成员

当某个成员不访问可变状态时,请将其标记为 nonisolated。这样的成员可以从任何位置同步运行,无需使用 await。

对于只由不可变数据构成的计算值,这种方式非常理想。

actor User {
    let id: Int
    var sessionCount = 0
    init(id: Int) { self.id = id }
    nonisolated var label: String { "User #\(id)" }
}

为什么 nonisolated 是安全的

nonisolated 成员只能读取不可变(let)状态,或其他 Sendable 状态。

编译器会拒绝从非隔离上下文访问可变的隔离状态。

actor User {
    let id: Int
    var sessionCount = 0
    init(id: Int) { self.id = id }
    // Error: cannot read mutable sessionCount here
    // nonisolated var bad: Int { sessionCount }
}

nonisolated 与协议

当参与者实现同步协议时,nonisolated 至关重要。协议方法不能是异步的,因此必须避免访问隔离状态。

actor Item: CustomStringConvertible {
    let name: String
    init(name: String) { self.name = name }
    nonisolated var description: String { "Item: \(name)" }
}

MainActor

@MainActor 是一个将代码隔离到主线程的全局参与者。界面更新应当放在这里。

您可以为类型、方法或属性添加注解,将它们固定到主参与者上。

@MainActor
final class ViewModel {
    var title = "Hello"
    func refresh() { title = "Updated" }
}

在参与者之间切换

从一个参与者调用另一个参与者时,运行时会在执行器之间切换并挂起。await 正是在这个挂起位置出现的。

actor Database { func load() -> Int { 42 } }
@MainActor
func show(_ db: Database) async {
    let v = await db.load() // hop to db actor
    print(v)               // hop back to main
}

参与者重入

参与者是可重入的:当一个方法执行到 await 时,参与者可能会先运行其他已排队的工作,然后再恢复 await 之后的执行。

您在 await 之前读取的状态可能已经在之后发生变化。请在挂起点之后重新检查假设。

actor Store {
    var ready = false
    func prepare() async {
        ready = false
        await Task.yield() // other calls may run here
        ready = true
    }
}

隔离参数

函数可以接受一个 isolated 参与者参数,使其函数体运行在该参与者上,即使这个函数本身不是该参与者的成员。

func bump(on counter: isolated Counter) {
    // runs isolated to counter; synchronous access
}

使用全局参与者管理子系统

您可以定义自己的全局参与者,将整个子系统(例如渲染流水线)隔离到单个执行器上。

@globalActor
actor RenderActor {
    static let shared = RenderActor()
}
@RenderActor func draw() { }

快速检查:隔离

请测试您对参与者隔离的理解。

回顾:参与者隔离与 nonisolated

参与者隔离会将对可变状态的访问串行化;跨参与者调用是异步的,并且需要使用 await。nonisolated 成员可以选择退出隔离,但只能读取不可变状态或 Sendable 状态,这对于实现同步协议至关重要。

@MainActor 会将代码固定到主线程,参与者是可重入的(状态可能在 await 前后发生变化),而全局参与者可以隔离整个子系统。掌握这些规则是实现安全并发的核心。

常见问题解答

「Actor 隔离与 nonisolated」课时是免费的吗?

是的 — 「Actor 隔离与 nonisolated」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 4 节课。

「Actor 隔离与 nonisolated」这节课中我会学到什么?

分析隔离边界。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Swift Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「Actor 隔离与 nonisolated」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Swift Academy 课中编写并运行代码吗?

能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 数据竞争问题
  2. Sendable 协议
  3. Actor 隔离与 nonisolated
  4. 迁移到严格并发
← 返回 Swift Academy