[英]Which sender is captured inside Actor message handler?
我是 Akka 演员的新手,我做了一些如下的实验来了解演员的工作原理。
class RequestActor extends Actor with ActorLogging {
import RequestActor._
implicit val timeout = Timeout(15.seconds)
implicit val ec: ExecutionContext = context.dispatcher
override def receive: Receive = {
case Request(name) =>
// self ? TempRequest(TempRequest(name), xxx) pipeTo sender // Q1: if we reference `sender` here, which `sender` will be captured?
self ? TempRequest(name, sender) onComplete {
// val whichSender = sender // Q2: if we reference `sender` here, which `sender` will be captured?
case Success(TempResponse(msg, origin)) => origin ! HelloReply(msg)
case Failure(ex) => ???
}
case TempRequest(name, origin) =>
sender ! TempReply(s"hello, ${name}!", origin)
case _ =>
???
}
}
我知道我们应该更愿意tell
ask
。 我编造了这个例子,试图消除一些困惑:
Q1 - Q2) 我知道sender
实际上是context.sender()
。 作为代码片段中的注释,将捕获哪个sender
?
我的困惑是, sender
是否会导致相应的ask
操作? 或者它可能是稍后的消息的sender
?
3) 演员在等待ask
回复时是否能够继续处理新消息?
从实验来看,似乎是这样。 谁能证实这一点?
非常感谢!
// 自己? TempRequest(TempRequest(name), xxx) pipeTo sender // Q1:如果我们在这里引用
sender
,会抓到哪个sender
?
消息Request
的发送者。 这在您的代码段中不可见。
来自评论
自己? TempRequest(TempRequest(name), xxx) pipeTo 发件人。 由于这是一个询问和等待,因此在收到响应之前,actor 可能会收到另一条消息,从而导致发送者发生变化。 那么,pipeTo 发送方是否有可能导致响应发送给错误的参与者?
pipeTo
模式将为返回的未来注册一个回调?
或ask
模式。 回调注册回调时会引用sender()
返回的发送方,在处理Request
消息时以阻塞方式完成。 因此sender()
是Request
消息的发送者。
pipeTo
排除了参与者上下文泄漏的任何可能性,这是应该使用它的原因之一。
// val whichSender = sender // Q2:如果我们在这里引用
sender
,会捕获哪个sender
?
这实际上会导致演员之外的演员上下文的错误或泄漏,并且不能这样做。 可以使用本地参考来完成,如下面的代码
case Request(name) =>
val requestSender = context.sender()
self ? TempRequest(name) onComplete {
case Success(TempResponse(msg)) => requestSender ! HelloReply(msg)
}
来自文档
当使用未来的回调,如 onComplete,或 map,如 thenRun,或 thenApply 内部演员时,您需要小心避免关闭包含演员的引用,即不要调用方法或从回调中访问封闭演员上的可变 state。 这会破坏actor封装,并可能引入同步错误和竞争条件,因为回调将同时调度到封闭的actor。 不幸的是,目前还没有一种方法可以在编译时检测这些非法访问。
最后
3) 参与者在等待请求回复时是否能够继续处理新消息?
是的。 没有“等待”过程。 它只是注册一个在actor外部执行的回调。 因此可能存在actor上下文泄漏的问题。
此外,
您可以使用forward
来保留原始邮件发件人。 您的代码可以简化如下
override def receive: Receive = {
case Request(name) =>
self.forward(TempRequest(name))
case TempRequest(name) =>
sender() ! HelloReply(s"hello, ${name}!"))
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.