是否可以在演员中使用Akka调度程序?

时间:2012-12-15 22:04:45

标签: scala akka scheduler

我希望有可能让演员入睡一会儿。演员应该决定自己要睡多久。由于Thread.sleep()不是推荐的方法,我想在akka中使用调度程序。因此我定义了一个演员是另一个演员可以注册被唤醒。

class Scheduler extends Actor {

  def receive = {
    case Sleep(duration) => context.system.scheduler.scheduleOnce(duration) {
      sender ! Ring
    }
  }
}

但发送方从未收到过Ring消息。 所以我的问题是

  • 是否在演员内部推荐调度程序?
  • 为什么发送方从未收到过Ring消息?
  • 如果不可能,解决问题的推荐方法是什么?

3 个答案:

答案 0 :(得分:44)

让我先回答标题问题:是的,可以在演员中使用调度程序。

case Sleep(duration) =>
  context.system.scheduler.scheduleOnce(duration, self, Ring)

现在回答问题背后的问题

你没有说出你真正想要达到的目标,所以我在这里做了一个有根据的猜测,你想让演员 - 通常做一些叫做“X”的东西 - 做一段叫做“Y”的事,暂停“X”活动。完整的解决方案是

class Sleepy extends Actor {
  def receive = {

    ... // cases doing “X”

    case Sleep(duration) =>
      case object WakeUp
      context.system.scheduler.scheduleOnce(duration, self, WakeUp)
      context.become({
        case WakeUp => context.unbecome()
        // drop the rest
      }, discardOld = false)
  }
}

使用FSM特性并在正常状态和睡眠状态之间切换也可以实现相同的效果。当然,你可以在睡觉时做任何你想做的事,例如混合使用Akka 2.1中的Stash特征,并在睡眠时调用stash()所有(或部分)消息,unstashAll()获取WakeUp消息时;或者你可以完全做其他事情。演员非常灵活。

演员不做什么

演员从不真正入睡,他们总是处理传入的消息。如上所示,您可以定义这意味着什么,但基本原则是您不能挂起一个actor,以便它不会处理其邮箱中的邮件。

答案 1 :(得分:16)

您正在关闭传递给调度程序的闭包中的“sender”。这意味着Ring消息很可能被发送给错误的actor。你应该这样做:

case Sleep(duration) => 
  val s = sender
  context.system.scheduler.scheduleOnce(duration) {
    s ! Ring
  }
}

答案 2 :(得分:0)

Roland Kuhn的回答涵盖了这个主题,我只是想补充一点,使用调度程序有另一个常见的用例: 当向另一个演员发送消息并等待这个演员回应时,通常会超时等待等待。

otherActor ! Request(...)
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
...
case Response(...) => ...
case WakeUp => context stop self