28

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

class Scheduler extends Actor {

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

但是发送方永远不会收到 Ring 消息。所以我的问题是

  • 是否建议在演员内部使用调度程序进行调度?
  • 为什么发送方永远不会收到 Ring 消息?
  • 如果这是不可能的,那么推荐的解决问题的方法是什么?
4

3 回答 3

45

先回答标题问题:是的,可以在actor内部使用调度器。

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 特征并在正常和睡眠状态之间切换来实现。当然,你可以在睡觉时做任何你想做的事情,例如混合StashAkka 2.1 中的 trait 并stash()在睡觉时调用所有(或部分)消息,unstashAll()当收到WakeUp消息时;或者你可以完全做其他事情。演员非常灵活。

演员不做什么

演员从不真正睡觉,他们总是处理传入的消息。如上所示,您可以定义这意味着什么,但基本原则是您不能暂停一个参与者,这样它就不会处理其邮箱中的消息。

于 2012-12-16T07:47:01.207 回答
16

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

case Sleep(duration) => 
  val s = sender
  context.system.scheduler.scheduleOnce(duration) {
    s ! Ring
  }
}
于 2012-12-15T22:21:20.293 回答
0

Roland Kuhn 的回答涵盖了这个主题,我只是想补充一点,使用调度程序还有另一个常见用例:当向不同的参与者发送消息并等待该参与者响应时,用超时来限制等待是很常见的.

otherActor ! Request(...)
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
...
case Response(...) => ...
case WakeUp => context stop self
于 2016-05-04T19:14:27.553 回答