Scala Akka 广播从 Parent 上下文向所有 child 演员发送消息

Scala Akka broadcasting send message to all child actors from Parent Context

在我的任务中 parent 演员创建一些 child 演员并向他们发送消息

def apply(): Behavior[CreateBranch] = {
     Behaviors.receive { (context, message) =>
        val child1 = context.spawn(Child(), "child1")
        val child2 = context.spawn(Child(), "child2")
        val child3 = context.spawn(Child(), "child3")

        context.children.foreach {
           child ! Child.SomeMessage
      {
  }
}

Child 演员定义为:

object Child {

     sealed trait SomeMessage
     def apply():Behavior[SomeMessage] = {
       // some behaviour
    {
}

但是表达式“context.children”不起作用:children 定义为 Iterable[ActorRef[Nothing]] 而不是 Iterable[ActorRef[Child.SomeMessage]]

在关于“context.children”的文档中 ActorContext.children

“当目的是向他们发送消息时,这不是查找 children 的有用方法。”

并且本文档提出了替代实现方式 - 但它大约有 30 行代码!

还有其他方法可以实现广播消息发送吗?

一般没有办法保证childactor的静态类型(parentactor和守护actor(context.system)也是一样) .

但是,如果您完全确定所有 children 都会接受您可以

context.children.foreach { child =>
  child.unsafeUpcast[Child.SomeMessage] ! Child.SomeMessage
}

顾名思义,这是不安全的,允许您在不保证 child 会处理它们的情况下发送消息。由于 Akka Typed Behavior 的实现涉及执行消息转换的经典 actor,因此 BehaviorActorRef 之间的不匹配会导致 actor 立即失败。 unsafeUpcast(至少从发件人的角度来看...)比 asInstanceOf 强制转换更安全,因为这至少可以保证您实际上是在 ActorRef 上调用 ! .

你问“有没有其他方法可以实现广播消息发送?”。

Levi 的回答在技术上是最正确的。但我认为“真正的”答案是不使用 context.children。这种复杂化是由于类型系统试图保护您免受一些非常合理的关注而引起的。 collection 包含所有 children。很多时候我可能会产生一个 child 只是为了监视超时、接收单个消息或其他可能无法理解该消息的任务。

如果你想向 child 演员发送特定消息,正如 Levi 的回答中所指出的,你可能并不是真正的意思是“所有 child 演员”,你的意思是“所有child 理解此消息的演员”。尽管还有一些其他方法可以做到这一点,但我总是发现最简单的方法就是为特定类型的 actor 维护自己的 collection ActorRefs。如果我有“工人演员”,我会维护自己的序列,然后消息类型就会自动工作。

我的经验是,您真的应该只将 context.children 用于 system-type 操作。但除此之外,我维护我自己的 collection。这样,如果我以后创建一种新型 child 演员,我不会破坏我对 child 演员的类型以及他们可以接收的消息所做的任何假设。