如何确定所有演员都收到了广播消息

时间:2014-09-28 23:56:54

标签: algorithm scala concurrency akka actor

我有一个ActorA,它从输入流中读取并向一组ActorB发送消息。当ActorA到达输入流的末尾时,它会清理其资源,向ActorB广播一个Done消息,并自行关闭。

我有大约12个ActorB发送消息给一组ActorC&#39。当ActorB收到来自ActorA的Done消息时,它会清理其资源并关闭自己,除了最后幸存的ActorB,它在关闭自己之前向ActorC广播一个Done消息。

我有大约24个ActorC发送消息到单个ActorD。与ActorB相似,当每个ActorC获得Done消息时,它会清理其资源并自行关闭,除了最后幸存的ActorC向ActorD发送Done消息。

当ActorD获得Done消息时,它会清理其资源并自行关闭。

最初我有ActorB&,并且ActorC在收到它时立即传播Done消息,但这可能导致ActorC在所有ActorB&之前关闭已经完成了他们的队列处理;同样,在ActorC处理完队列之前,ActorD可能会关闭。

我的解决方案是使用在ActorB&#39>之间共享的AtomicInteger

class ActorB(private val actorCRouter: ActorRef,
             private val actorCount: AtomicInteger) extends Actor {
  private val init = {
    actorCount.incrementAndGet()
    ()
  }

  def receive = {
    case Done => {
      if(actorCount.decrementAndGet() == 0) {
        actorCRouter ! Broadcast(Done)
      }
      // clean up resources
      context.stop(self)
    }
  }
}

ActorC使用类似的代码,每个ActorC共享一个AtomicInteger。

目前,所有参与者都是在一个Web服务方法中初始化的,下游的ActorRef是在上游演员中传递的。构造

是否有首选方法可以执行此操作,例如使用Akka方法而不是AtomicInteger?


编辑:我考虑以下作为一种可能的选择:当一个演员收到一个Done消息时,它将接收超时设置为5秒(程序将花费一个多小时来运行,因此延迟清理/关闭几秒钟不会影响表现);当actor获得ReceiveTimeout时,它会向下游actor广播Done,清理并关闭。 (ActorB和ActorC的路由器使用SmallestMailboxRouter)

class ActorB(private val actorCRouter: ActorRef) extends Actor {

  def receive = {
    case Done => {
      context.setReceiveTimeout(Duration.create(5, SECONDS))
    }

    case ReceiveTimeout => {
      actorCRouter ! Broadcast(Done)
      // clean up resources
      context.stop(self)
    }
  }
}

1 个答案:

答案 0 :(得分:1)

在相关演员之间共享actorCount并不是一件好事。 Actor应该只使用自己的状态来处理消息。 如何为ActorB类型的actor拥有ActorBCompletionHanlder actor。所有ActorB都会引用ActorBCompletionHanlder actor。每次当ActorB收到Done消息时,它都可以进行必要的清理并简单地将完成的消息传递给ActorBCompletionHanlder。 ActorBCompletionHanlder将维持状态变量以维持计数。每次收到完成的消息,它都可以简单地更新计数器。因为这只是这个actor的状态变量,所以不需要原子,这样就不需要任何显式锁定。一旦接收到最后完成的消息,ActorBCompletionHanlder将向ActorC发送完成消息。 这样,activeCount的共享不是演员之间,而是由ActorBCompletionHanlder管理。对于其他类型,可以重复相同的事情。

A-> B's - > BCompletionHanlder - > C' - > CCompletionHandler - > d

其他方法可能是让一个监督演员与evey相关的演员组合。在监视器上使用监视api和子终止事件,您可以选择在收到上一个完成的消息后决定该做什么。

val child = context.actorOf(Props[ChildActor])
    context.watch(child)

    case Terminated(child) => {
        log.info(child + " Child actor terminated")
    }