从演员内部的未来回到 "sender"

Returning to "sender" from a future inside an actor

我想做这样的事情-

class MyActor extends Actor {
....
override def receive = {
  case msg =>
     .... // do something
     Future {
       ... // calculate response
       sender ! response
     }
}
}

// in some other code -
val future = myActorRef ? msg
future.onSuccess {
    ....
}

这行得通吗?换句话说,Akka 的 "ask" 实现是否关心响应是否在 "receive" 方法完成之前发回?

是的,它会起作用,甚至还有一个内置的 akka 模式 - pipe:

import akka.pattern.pipe

override def receive = {
  case msg =>
    .... // do something
    Future {
      ... // calculate response
      response
    } pipeTo sender()
}

但是您应该注意代码中的一些注意事项:

sender 是一个函数,因此,当您的 Future{...} 块中的代码执行时,参与者可能正在处理来自另一个发件人的消息,因此您可能会回复错误的发件人。为避免这种情况,请在闭包之外评估您的发件人:

val mySender = sender()
Future {
  ... // calculate response
  mySender ! response
}

不过,如果您使用 pipe,则无需担心这一点。


你正在将一个未来包装到一个演员中,并用 ask 调用那个演员,这又给了你一个未来。你真的应该考虑直接调用未来,而不是演员。 如果你真的需要演员,例如因为你正在隔离一些可变状态或消息排序很重要,你应该知道计算 Future 不会发生在演员的线程上,所以你正在失去你的状态一致性和消息排序 - 考虑失去的另一个原因演员,并直接调用未来。

问题是,当执行 future 时,sender 可能不再有效。你有几个选择,这里有两个是我想到的:

您可以捕获未来sender之前的

override def receive = {
  case msg =>
     .... // do something
     val replyTo = sender

     Future {
       ... // calculate response
       replyTo ! response
     }
}

或者您可以使用 pipeTo 模式:

override def receive = {
  case msg =>
     .... // do something
     import akka.pattern.pipe

     Future {
       ... // calculate response
     }.pipeTo(sender())
}