Actor

4 阅读2分钟

Swift Actor 是 Swift 并发编程模型的一部分,从 Swift 5.5 开始引入。Actor 用于管理共享状态,通过隔离确保对状态的互斥访问,从而避免数据竞争。以下是关于 Swift Actor 的详细说明:

  1. Actor 的定义

    • Actor 是一种引用类型,类似于类,但不同之处在于 Actor 一次只允许一个任务访问其可变状态。
    • 定义 Actor 使用 actor 关键字。
  2. Actor 的特性

    • Actor 内部的状态(属性和方法)默认是隔离的,外部代码不能直接访问,除非通过 await 调用。
    • Actor 内部可以定义方法和属性,其中方法分为两种:可异步访问的和不可异步访问的(但外部访问都必须通过 await)。
    • Actor 内部可以定义同步方法,但外部调用时仍然需要 await,因为调用可能会被挂起直到 Actor 空闲。
  3. Actor 的使用场景

    • 当多个任务需要访问和修改共享数据时,使用 Actor 可以保证数据安全。
    • 例如,多个任务同时操作一个计数器,使用 Actor 可以确保每次修改都是原子的。
  4. Actor 的示例

 actor Counter {
 private var value = 0
    func increment() -> Int {
        value += 1
        return value
    }
    func getValue() -> Int {
        return value
    }
  }
// 使用 Actor
let counter = Counter()
Task {
    let value = await counter.increment()
    print(value) // 输出 1
}
Task {
    let value = await counter.increment()
    print(value) // 输出 2
}

  1. Actor 的注意事项

    • 不能直接从一个 Actor 内部方法中调用另一个 Actor 的方法,因为可能会造成死锁。如果需要,可以使用 async 方法并 await 调用。
    • Actor 内部可以使用 nonisolated 关键字标记不需要隔离的成员,这样外部访问时就不需要 await
  2. Actor 与数据竞争

    • Actor 通过隔离状态来防止数据竞争,但并不能防止所有的并发问题,比如死锁。因此,在设计 Actor 时需要注意避免长时间占用 Actor 而导致其他任务等待。
  3. Actor 与 @MainActor

    • @MainActor 是一个特殊的 Actor,它运行在主线程上,用于更新 UI。任何标记为 @MainActor 的代码都必须运行在主线程上。
  4. Actor 的性能

    • Actor 通过串行队列来管理任务,所以如果 Actor 中的任务执行时间很长,会阻塞其他等待该 Actor 的任务。因此,在 Actor 中应避免执行耗时操作。
  5. Actor 的继承

    • Actor 不能继承自其他类或 Actor,但可以遵守协议。
  6. Actor 和 Sendable

    • Actor 内部的状态必须是 Sendable 的,即可以安全地在并发环境中传递。这包括值类型、不可变类或本身是 Actor 的类型。

Swift Actor 是 Swift 并发模型的核心组成部分,用于安全地管理共享状态,防止数据竞争。