我很好奇是否可以安全地实现自动取消轮询,而不使用var来保留akka.actor.Cancellable
的实例
到目前为止,我想出了类似于下面示例中所示的内容。但是,我很好奇是否可以安全地假设在热交换发生之前永远不会发送“tick”消息,即调度轮询器的行:
tick(1, 5, context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick"))
基本上与:
相同val poll = context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick")
tick(1, 5, poll)
所以,我认为在某些情况下,在热交换有机会发生之前会收到第一个滴答声......想法?
import akka.actor.{Cancellable, ActorSystem}
import akka.actor.ActorDSL._
import concurrent.duration._
object PollerDemo {
def run() {
implicit val system = ActorSystem("DemoPoller")
import system.dispatcher
actor(new Act{
become {
case "tick" => println("UH-OH!")
case "start" =>
become {
tick(1, 5, context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick"))
}
}
def tick(curr:Long, max:Long, poll:Cancellable):Receive = {
case "tick" => {
println(s"poll $curr/$max")
if(curr > max)
cancel(poll)
else
become{ tick(curr + 1, max, poll) }
}
}
def cancel(poll:Cancellable) {
println("cancelling")
poll.cancel()
println(s"cancelled successfully? ${poll.isCancelled}")
println("shutting down")
context.system.shutdown()
}
}) ! "start"
system.awaitTermination(1 minute)
}
}
答案 0 :(得分:3)
我的猜测是你的代码没问题。请记住,演员一次只能处理一个邮箱。当您收到start
消息时,您设置了一个计时器,它将向邮箱传递另一条消息,然后您交换接收实现。因为您在处理start
消息时执行接收交换,所以在处理邮箱中的下一条消息之前,您已经更改了actor的接收行为。因此,当它继续处理tick
消息时,您可以确定它将使用新的接收行为。
您可以通过在第一个tick
内发送其他become
消息来验证这一点,如下所示:
become {
self ! "tick"
tick(1, 5, context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick"))
}
这里我们确实从等式中消除了计时器,当询问在成为块期间发送的消息是否将由旧接收或新接收处理时。我没有运行这个,但根据我的理解或akka,这两个滴答应该由新的接收处理。
答案 1 :(得分:1)
你真的不能用演员进行纯函数式编程。发送消息是一种副作用。由于它们的接收函数不返回结果,所有演员在接收消息时都可以做到副作用。几乎你的代码所做的每件事都是副作用
您可能在代码实现中避免变量,但become
正在改变Actor超类中的var。 context.system.scheduler.schedule
显然是副作用,并在某处改变状态。 cancel
所做的每一件事都是副作用。 system.awaitTermination(1 minute)
不是函数......