akka 2.0向自己发送消息

时间:2014-03-11 08:04:31

标签: scala akka

使用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)

3 个答案:

答案 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

这使我可以要求结果,但要付出一些额外的开销。