繁体   English   中英

在 Actor 消息处理程序中捕获了哪个发件人?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM