使用Akka 2.0尝试向自己发送消息(使用ask模式)
import akka.pattern.ask
import scala.concurrent.{Await, Future}
import akka.actor.{Props, Actor, ActorSystem}
import scala.concurrent.duration._
import akka.util.Timeout
object askTest extends App{
implicit val timeout = Timeout(5 seconds)
val system = ActorSystem("AskTestSystem")
val myActor = system.actorOf(Props(new TestActor), name = "myActor")
val future: Future[Foo] = ask(myActor, Foo("test")).mapTo[Foo]
val result = Await.result(future, timeout.duration)
println(result)
}
case class Foo(name:String){
override def toString = "Foo "+name
}
class TestActor extends Actor {
def receive = {
case Foo(a) => self ! Foo("buzz "+a)
case any => println(any+" that was unexpected")
}
}
然而,它与Timeout异常崩溃并带有以下跟踪:
Exception in thread "main" java.util.concurrent.TimeoutException: Futures timed out after [5 seconds]
at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:96)
at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:100)
at scala.concurrent.Await$$anonfun$result$1.apply(package.scala:107)
at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
at scala.concurrent.Await$.result(package.scala:107)
at akkaTest.askTest$delayedInit$body.apply(askTest.scala:33)
at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:71)
at scala.App$$anonfun$main$1.apply(App.scala:71)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
at scala.App$class.main(App.scala:71)
at akkaTest.askTest$.main(askTest.scala:13)
at akkaTest.askTest.main(askTest.scala)
答案 0 :(得分:6)
您的代码执行您告诉它要做的事情:演员无限期地向自己发送消息。因为它将消息发送给除self以外的任何人,所以ask
模式无法正常工作,因为ask
正在等待将消息发送到发件人,而不是自
self
是对当前actor的引用,当你希望actor向自己发送消息时,你可以使用它。 sender
是对已发送当前正在处理的消息的actor的引用。如果您想“回复”发件人,请使用它。
ask
模式创建一个隐式actor,它在目标actor中成为sender
引用 - 这是非常自然的。因此,您需要将self ! Foo("buzz " + a)
更改为sender ! Foo("buzz " + a)
,您的代码才能生效。
答案 1 :(得分:4)
您可以向self
发送消息,但不能等待回复。因为在完成处理当前消息之前不会收到新消息,并且如果使用ask
,在收到新消息的回复之前,您将无法完成当前消息的处理!所以你正在制造僵局。
但是对于有问题的代码,您不要求self
回复。由ask
创建的演员正在等待myActor
的回复,但未获得该回复(因为TestActor
的代码未发送任何回复 ,并向self
发送消息。
您可以通过稍微更改self ! message
来看到TestActor
的作用:
case class Bar(name: String)
class TestActor extends Actor {
def receive = {
case Foo(a) => self ! Bar(a)
case Bar(a) => println("Got a message to self: " + a)
case any => println(any+" that was unexpected")
}
}
答案 2 :(得分:0)
道歉,我知道这确实是一个老问题,但最近在我的用例中浮出水面。只是想分享我的2美分。
我想通过将消息路由到具有更新参数的self来处理消息。我期望通过使用Ask模式获得结果。为了使此工作正常进行,我不得不使用第二个代理角色,其主要目的是将消息中继回主要角色。
(augmented)
Main Actor --> Proxy Actor --> Main Actor
ask ask
这使我可以要求结果,但要付出一些额外的开销。