scala 是否可以在 actor 中使用 Akka 调度程序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13896638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to use the Akka scheduler inside an actor?
提问by Felix Reckers
I want to have the possibility to put actors to sleep for a while. The actors should decide themselves how long they are going to sleep. As Thread.sleep() is not a recommended way of doing this I thought of using the scheduler in akka. I therefore defined an actor were another actor can register for being woken up.
我希望有可能让演员们睡一会儿。演员们应该自己决定他们要睡多久。由于 Thread.sleep() 不是推荐的这样做的方法,我想在 akka 中使用调度程序。因此,我定义了一个演员,另一个演员可以注册被唤醒。
class Scheduler extends Actor {
def receive = {
case Sleep(duration) => context.system.scheduler.scheduleOnce(duration) {
sender ! Ring
}
}
}
But the sending actor never receives the Ring message. So my questions are
但是发送参与者永远不会收到 Ring 消息。所以我的问题是
- Is scheduling with the scheduler recommended inside an actor?
- Why is the sending actor never receiving the Ring message?
- If this is not possible what is the recommended way of solving the problem?
- 是否推荐在 actor 内部使用调度程序进行调度?
- 为什么发送方从未收到 Ring 消息?
- 如果这是不可能的,推荐的解决问题的方法是什么?
回答by Roland Kuhn
Let me first answer the title question: yes, it is possible to use the scheduler inside an actor.
让我首先回答标题问题:是的,可以在演员内部使用调度程序。
case Sleep(duration) =>
context.system.scheduler.scheduleOnce(duration, self, Ring)
Now to the question behind the question
现在到问题背后的问题
You did not say what you actually want to achieve, so I'm making an educated guess here that you want the actor—which normally does something called “X”—to do something called “Y” for a while, suspending the “X” activity. The full solutions to this would be
你没有说出你真正想要达到的目标,所以我在这里做了一个有根据的猜测,你希望演员——通常会做一些叫做“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)
}
}
The same could as well be implemented using the FSM trait and switching between the normal and the sleeping state. And of course you can do whatever you want while sleeping, e.g. mix in the Stashtrait in Akka 2.1 and call stash()for all (or some) messages while sleeping, unstashAll()when getting the WakeUpmessage; or you could do something else altogether. Actors are very flexible.
使用 FSM 特性并在正常和睡眠状态之间切换也可以实现相同的功能。当然,你可以在睡觉时做任何你想做的事,例如Stash在 Akka 2.1 中混合trait 并在收到stash()消息时在睡觉unstashAll()时调用所有(或一些)WakeUp消息;或者你可以完全做其他事情。演员非常灵活。
What actors don't do
演员不做的事
Actors never really sleep, they always handle incoming messages. As shown above, you can define what that means, but the basic principle is that you cannot suspend an actor such that it will not process the messages in its mailbox.
Actors 从不真正睡觉,他们总是处理传入的消息。如上所示,您可以定义这意味着什么,但基本原则是您不能挂起一个 actor,使其不处理其邮箱中的消息。
回答by Ryan LeCompte
You are closing over "sender" in your closure that's passed to the scheduler. This means that the Ring message is most likely being sent to the wrong actor. You should do this instead:
您正在关闭传递给调度程序的关闭中的“发送者”。这意味着 Ring 消息很可能被发送到错误的参与者。你应该这样做:
case Sleep(duration) =>
val s = sender
context.system.scheduler.scheduleOnce(duration) {
s ! Ring
}
}
回答by Eyal Farago
Roland Kuhn's answer covers the subject, I just wanted to add that there's another common use-case for using the scheduler: when sending a message to a different actor and waiting for this actor to respond, it's quite common to cap the wait with a timeout.
罗兰·库恩 (Roland Kuhn) 的回答涵盖了该主题,我只想补充一点,使用调度程序还有另一个常见用例:当向不同的参与者发送消息并等待该参与者响应时,用超时来限制等待是很常见的.
otherActor ! Request(...)
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
...
case Response(...) => ...
case WakeUp => context stop self

