当将来使用tell时,Akka会回复任何内容

时间:2015-07-13 15:48:00

标签: scala akka

下面的代码使用2个问题,最初似乎应该打印&#34;这应该在actor1中打印,但大部分时间都不会因为接收方法完成的竞争条件而导致&#34; < / strong>即可。 然而,在“接收”之间似乎存在竞争条件。方法完成和未来的整理,因此没有打印。 这是akka的预期行为吗?这是一个错误吗? 我试图避免使用&#39;问&#39;尽可能使用&#39;告诉&#39;相反,但有时候它是必须的。

import akka.actor._
import akka.routing.SmallestMailboxPool
import akka.util.Timeout
import akka.pattern.ask
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}

object ActorsAskingStuff extends App {
  val system = ActorSystem("abc-system")
  val actor1 = system.actorOf(Props[Actor1].withRouter(SmallestMailboxPool(1)), "actor1")
  actor1 ! 5
}

class Actor1 extends Actor {
  implicit val timeout = Timeout(60 seconds)
  val actor2: ActorRef = context.actorOf(Props[Actor2].withRouter(SmallestMailboxPool(1)), "actor2")
  override def receive: Receive = {
    case _ =>
      println("actor1 was called")
      actor2 ? "hello" onComplete {
      case Success(a) => println(a)
      case Failure(b) => println("FAILURE")
    }
  }
}

class Actor2 extends Actor {
  implicit val timeout = Timeout(6 seconds)
  val actor3: ActorRef = context.actorOf(Props[Actor3].withRouter(SmallestMailboxPool(1)), "actor3")
  override def receive: Actor.Receive = {
    case _ =>
      println("actor2 was called")
      actor3 ? "hello" map {
        _ =>
          println("Actor2 completed the future")
          sender ! "This should be printed in actor1 but most of the time wont because of a race condition with the receive method finishing"
      }

      // uncomment this to make it work
      //Thread.sleep(100)
  }
}

class Actor3 extends Actor {
  override def receive: Actor.Receive = {
    case _ =>
      println("actor3 was called")
      sender ! "I'm actor3"
  }
}

1 个答案:

答案 0 :(得分:3)

执行此操作时,您将关闭sender

actor3 ? "hello" map {
  _ =>
    println("Actor2 completed the future")
    sender ! "This should be printed in actor1 but most of the time wont because of a race condition with the receive method finishing"
}

此时sender可能已发生变化。为了避免关闭sender,您可以像这样重写:

val originator = sender()
actor3 ? "hello" map {
  _ =>
    println("Actor2 completed the future")
    originator ! "This should be printed in actor1 but most of the time wont because of a race condition with the receive method finishing"
}

在此时进入基于Future的回调(例如onCompletemap)后,演员认为已完成当前消息的转发并转到下一条消息在邮箱中(如果有)。发生这种情况时,sender()只是一个def,它返回可能发生变化的var的值,它将返回新的ActorRef(更多消息)或没有(deadletter)如果没有消息。

您可以查看此帖子了解更多信息: sender inside a future