SuperAPI AI 工具集

kp-actor-pattern

智能体与模型

查看项目

更新于 10-16 16:28

技能介绍

用途

该技能用于把可变状态(计数器、缓存、内存聚合、会话状态等)限制在单个协程内部,外部代码通过 Channel 向该协程发送消息。协程一次处理一条消息,状态因此隐式地单线程访问,不需要锁。

主要能力

  • 用 sealed interface 定义消息类型,每个变体对应 actor 支持的一个操作;sealed 类使 when 可以穷尽检查,编译器强制处理每类消息。
  • 在 launch 的协程内部声明并持有可变状态(var 或任意可变结构),外部代码拿不到该状态的引用。
  • 外部通过 Channel 发送消息,actor 的 for (msg in ch) 循环逐条处理。
  • 查询类消息通过 CompletableDeferred 回传:发送方附上一个 CompletableDeferred,actor 完成后发送方 await(),避免泄漏返回通道。

核心代码

sealed interface CounterMsg {
    data class Add(val n: Int) : CounterMsg
    data class Get(val reply: CompletableDeferred<Int>) : CounterMsg
}

fun CoroutineScope.counterActor(): SendChannel<CounterMsg> {
    val ch = Channel<CounterMsg>()
    launch {
        var count = 0
        for (msg in ch) when (msg) {
            is CounterMsg.Add -> count += msg.n
            is CounterMsg.Get -> msg.reply.complete(count)
        }
    }
    return ch
}

// Usage:
val actor = scope.counterActor()
actor.send(CounterMsg.Add(3))
val reply = CompletableDeferred<Int>()
actor.send(CounterMsg.Get(reply))
println(reply.await())   // 3

三个组成部分:sealed 消息类型、持有状态的协程、外部 Channel。

文档提到,Kotlin 曾提供 actor { … } 协程构建器,但已被废弃;推荐按上述方式手工实现该模式。

使用方式

创建 actor(返回 SendChannel),向该通道 send 消息,查询时附带 CompletableDeferred 并 await 结果。

适用场景

  • 协调对一小块状态的并发更新(计数器、缓存、内存聚合、会话状态)。
  • 当状态上的操作可以明确枚举为一小组消息类型时,替代 Mutex + var 组合。
  • 建模一个状态随命令流(AddItem、RemoveItem、Clear 等)演进的有状态服务。
  • 当状态需要命令而不只是观察,StateFlow 不太合适时。

不适用场景

  • 状态被许多消费者观察但很少更新 → StateFlow 更简单。
  • 操作彼此独立、无需协调 → 不需要 actor。
  • 状态确实复杂且有许多不变式 → 考虑带内部锁的数据结构是否更清晰。

决策启发式

  • 当状态的操作可以枚举为有限、有名字的集合(sealed 消息层次)时,actor 是合适的工具。
  • “读多写少”的共享状态 → 用 StateFlow,不用 actor。
  • “写多读少” → 用 actor。
  • 保持消息词汇表小;如果 sealed 层次超过约 6 个变体,重新考虑设计。
  • 只有在确定 actor 能跟上时才用 Channel.UNLIMITED;否则优先 BUFFERED,让背压可见。

反模式

  • 通过“给我引用”的消息暴露内部状态,破坏封装,调用方获得共享状态访问权。
  • 让 actor 阻塞在长时间外部操作上,其他消息会堆积;应把慢操作交给子协程,保持 actor 主循环轻快。
  • 持续负载下使用无界容量通道,导致堆内存膨胀。
  • 两个 actor 同步来回通信,容易死锁;尽量设计无环的消息流。

相关内容

文档列出 kp-channels(actor 使用的消息传递原语)、kp-sealed-when(消息类型是 sealed 层次并用穷尽 when)、kp-select(actor 需等待多个来源时有用)、kp-flow-cold-vs-hot(共享可观察状态真正需要时,StateFlow 优于 actor)、gof-state(actor 内部常承载状态机)。

参考

  • Kotlin Coroutines(Marcin Moskała)——actor 模式章节。
  • Kotlin 协程官方指南——共享可变状态与并发,“actors”小节。