非阻塞计时器任务和Akka Actors

时间:2017-08-30 11:51:58

标签: java timer akka

请注意:虽然我喜欢使用Akka的Java API(这是我正在使用的)的解决方案,但我和#39;对任何有效的解决方案感到满意,并且可能想出如何将基于Scala的答案转换为Java-land。

我有一个拥有许多演员的Akka应用,其中两个是FizzBuzzFizz actor可以接受两种类型的消息:

  • StartNewTimerTask;和
  • ResetAllTimerTasks

Buzz演员只接受DoItNow消息。这些参与者与系统其余部分之间的消息流如下:

  1. 任何事物(其他参与者,甚至事件驱动的组件之外的演员系统)都可以随时向StartNewTimerTask演员发送Fizz消息
  2. 每次Fizz actor收到StartNewTimerTask消息时,它会创建并启动一个新的异步/非阻塞计时器,尝试运行,例如8秒。如果计时器到达结尾(8秒),则会向DoItNow演员发送Buzz消息
  3. Fizz演员可以接受任意数量的并发StartNewTimerTask消息,因此可以"管理"可能同时有多个计时器,每个计时器都计入8秒的魔法数字。因此,如果其他20个演员在几秒钟内向StartNewTimerTask演员发送Fizz个消息,那么Fizz演员将会管理" 20个非阻塞,独立的定时器同时。当这20个计时器中的每一个达到各自的8秒持续时间时,他们会向DoItNow演员发送20条独立的Buzz消息
  4. Fizz演员收到ResetAllTimerTasks条消息时,当前正在进行的任何计时器"将被中断/取消(以便他们停止倒计时到8秒的持续时间,从而阻止他们向DoItNow发送Buzz消息。因此,借用上面的示例,如果时间t=1t=3 Fizz行为者收到了20条StartNewTimerTask条消息,那么t=10或许可能有14条消息DoItNow计时器会过去并发出Fizz条消息,也许还有6条消息正在进行中。如果在确切时刻ResetAllTimerTasks收到Buzz消息,则会阻止这6个定时器发送和触发消息,因此在此示例DoItNow中只会收到14 TimerTask消息
  5. 我知道Java 8 API(没有Akka)主张扩展Timer#scheduleAtFixedRate并将这些任务提交到// Groovy pseudo-code class MyTimerTask extends TimerTask { @Inject ActorRef buzz @Override void run() { // No op! } void completeTask() { buzz.tell(new DoItNow(), null) } } class Fizz extends UntypedAbstractActor { @Inject Timer timer @Override void onReceive(Object message) { if(message in StartNewTimerTask) { timer.scheduleAtFixedRate(new MyTimerTask(), 0, 8 * 1000) } else if(message in ResetAllTimerTasks) { timer.cancel() } } } class Buzz extends UntypedAbstractActor { @Override void onReceive(Object message) { if(message in DoItNow) { // Do something super cool now... } } } 方法,但我不确定是否与Akka完全冲突或如果有更好的方法来使用Akka API实现此功能。到目前为止我最好的尝试:

    def sum_odd_n(n):
    while n<2*n: # n will always be less than ('<') 2*n. For eg, if n=5, 5<10.
        sum = 0 # you are resetting the sum at every iteration. We need to take this outside.
        if n%2==1:
            sum = sum+n
    return (sum)
    

    但是,我不认为我正确管理计时器或充分发挥Akka调度程序/计时器API的潜力。 有什么想法吗?

1 个答案:

答案 0 :(得分:1)

考虑避免使用Java Timer API以支持刚刚与Akka 2.5.4一起发布的新actor timer功能。演员计时器允许演员使用一个或多个与其生命周期相关联的内部计时器来定期向自己发送消息。要在Java中访问此功能,只需将Fizz actor更改为扩展AbstractActorWithTimers

以下示例位于Scala中(在Scala中,混合使用Timers特征):

object Fizz {
  private case object SendToBuzz
}

class Fizz(buzz: ActorRef) extends Actor with Timers {
  import Fizz._

  def receive = {
    case StartNewTimerTask =>
      val uuid = java.util.UUID.randomUUID
      timers.startPeriodicTimer(uuid, SendToBuzz, 8.seconds)
    case ResetAllTimerTasks =>
      timers.cancelAll()
    case SendToBuzz =>
      buzz ! DoItNow
  }
}
  • Fizz actor处理StartNewTimerTask消息时,它会启动一个新的计时器,该计时器会向SendToBuzz发送self消息(即{{1}演员)每八秒钟。
  • Fizz处理Fizz消息时,它会向SendToBuzz演员发送DoItNow消息。
  • Buzz处理Fizz消息时,它会取消所有计时器。
  • 如果重新启动或停止ResetAllTimerTasks,则会自动取消所有计时器。