Meet distributed actors in Swift
System & Services 进阶 20m

认识 Swift 中的分布式 Actor

Meet distributed actors in Swift

2022年6月6日

在 Apple 官方观看视频

一句话判断

Distributed Actors 把 Swift 的并发安全模型从单进程扩展到了多进程——Actor 隔离 + 位置透明性,让分布式系统的代码和本地代码一样安全。

这场 Session 讲了什么

Swift Actor 通过编译时检查防止数据竞争,但只限于同一进程内。Distributed Actors 将这个模型扩展到跨进程(多设备、集群、服务器)场景。

核心概念是”位置透明性”:无论 Distributed Actor 在本地还是远程,交互方式完全一样。这意味着你可以在本地测试完整的分布式逻辑,部署时不需要修改实现代码。

Session 用一个井字棋游戏(Tic Tac Fish)演示了从普通 Actor 迁移到 Distributed Actor 的过程。关键步骤包括:添加 distributed 关键字、指定 ActorSystem 类型、处理 ID 属性的自动生成、以及理解 distributed 方法的序列化要求。

Swift 5.7 引入了 Distributed 模块,包含 DistributedActor 协议和相关类型。目前提供了 LocalTestingDistributedActorSystem 用于本地开发和测试。

值得深挖的点

  • 位置透明性的价值:同一个 Distributed Actor 可以在本地运行(测试),也可以在远程节点运行(生产)。调用方不需要知道也不需要关心。这大大简化了分布式系统的开发和测试。
  • ActorSystem 的职责:ActorSystem 负责所有序列化和网络通信。你可以选择不同的实现(比如基于 gRPC 的系统)。Swift 提供了 LocalTesting 系统用于开发。
  • Distributed 方法的限制:标有 distributed 的方法参数和返回值必须可序列化(遵循 Codable)。编译器会检查这一点。非 distributed 方法不受此限制。
  • ID 的自动管理:Distributed Actor 的 ID 由 ActorSystem 分配,全局唯一。不能手动定义 id 属性——编译器会报错。

代码片段

import Distributed

// 使用本地测试 Actor System
typealias DefaultDistributedActorSystem = LocalTestingDistributedActorSystem

// 将普通 Actor 转换为 Distributed Actor
distributed actor BotPlayer {
    // 不需要手动定义 id,编译器自动生成
    typealias ActorSystem = LocalTestingDistributedActorSystem

    var moveCount: Int = 0
    let team: Team

    distributed func generateMove() -> GameMove {
        moveCount += 1
        return GameMove(
            position: calculatePosition(),
            emoji: team.emoji(for: moveCount)
        )
    }

    distributed func opponentDidMove(_ move: GameMove) {
        // 处理对手的移动
    }
}

// 使用方式与普通 Actor 相同——无论本地还是远程
let bot = BotPlayer(system: actorSystem, team: .fish)
let move = try await bot.generateMove()  // 远程调用看起来和本地一样

// 玩家 Actor 也可以是 Distributed 的
distributed actor HumanPlayer {
    typealias ActorSystem = LocalTestingDistributedActorSystem

    let team: Team
    weak var gameModel: GameModel?

    distributed func generateMove() -> GameMove {
        // 等待人类玩家选择
    }
}

最佳实践

  • 先用 LocalTesting 系统开发和测试,确认逻辑正确后再接入真实的 ActorSystem
  • 所有需要远程调用的方法标记 distributed,内部辅助方法不要标记
  • Distributed Actor 的参数和返回值必须遵循 Codable
  • ID 是全局唯一标识符,可以用于路由和查找 Actor
  • 在同一进程内使用 Distributed Actor 的开销极低,不要因为担心性能而避免使用

还有什么值得关注

  • “Protect mutable state with Swift actors”(WWDC 2021)是前置内容
  • Swift Distributed Actors 是 Swift on Server 的关键技术
  • ActorSystem 的具体实现可以基于不同的网络协议
  • 这个功能目前是 Swift 5.7 的一部分,但标记为 experimental
  • 社区已经有基于 gRPC 和其他协议的开源 ActorSystem 实现
WWDC 2022