Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
可以在Scala中等待第二次响应吗_Scala_Akka_Actor - Fatal编程技术网

可以在Scala中等待第二次响应吗

可以在Scala中等待第二次响应吗,scala,akka,actor,Scala,Akka,Actor,假设我有演员A。 A希望接收消息,一旦接收到消息,它将返回两条消息 A extends Actor { def receive: Receive = { case M1 => context.sender ! M2 context.sender ! M3 } } 在演员A中,我想发送一条消息,然后等待两个回复。 我知道这样的回答很容易 val task = A ? M1 Await.result(task, timeout) 但我不确定这是否可能

假设我有演员A。 A希望接收消息,一旦接收到消息,它将返回两条消息

A extends Actor {
  def receive: Receive = {
    case M1 =>
      context.sender ! M2
      context.sender ! M3
  }
}
在演员A中,我想发送一条消息,然后等待两个回复。 我知道这样的回答很容易

val task = A ? M1
Await.result(task, timeout)
但我不确定这是否可能与两个连续的消息


发送两条单独的消息很重要,因为我只需要在另一个地方等待其中的第一条消息。

将包含M2和M3的元组返回给发送者如何

import akka.pattern.ask
import akka.actor.{Props, ActorSystem, Actor}
import akka.util.Timeout
import com.test.A.{M1, M2, M3}

import scala.concurrent.Await
import scala.concurrent.duration._

object Test extends App {

  implicit val timeout = Timeout(5 seconds)

  val system = ActorSystem("test-system")
  val actor = system.actorOf(Props[A], name = "a-actor")
  val future = actor ? M1
  val await = Await.result(future, Duration.Inf)
  println(await)

}

class A extends Actor {
  override def receive: Receive = {
    case M1 => sender() ! (M2, M3)
  }
}

object A {
  case object M1
  case object M2
  case object M3
}
运行此操作将导致:

(M2,M3)

在确实需要等待两条消息的情况下,可以通过引入中间参与者来解决此问题

这个演员看起来像这样:

class AggregationActor(aActor: ActorRef) extends Actor {

  var awaitForM2: Option[M2] = None
  var awaitForM3: Option[M3] = None
  var originalSender: Option[ActorRef] = None

  def receive: Receive = {
    case M1 =>
      // We save the sender
      originalSender = Some(sender())
      // Proxy the message
      aActor ! M1
    case M2 =>
      awaitForM2 = Some(M2)
      checkIfBothMessagesHaveArrived()
    case M3 =>
      awaitForM3 = Some(M3)
      checkIfBothMessagesHaveArrived()
  }

  private def checkIfBothMessagesHaveArrived() = {
    for {
      m2 <- awaitForM2
      m3 <- awaitForM3
      s <- originalSender
    } {
      // Send as a tuple
      s ! (m2, m3)
      // Shutdown, our task is done
      context.stop(self)
    }
  }

}

您是否愿意创建另一个代理M1并等待M2和M3的参与者?是的,但在另一个参与者中,我们需要等待M2和M3都收到。有什么方法可以做到这一点?如果你想异步等待M2和M3,那就很棘手了,因为我需要确保M3是从actor AI的相应实例发送的。我的同事听说这太棘手了,甚至不可能,因为akka不是为此而设计的,正确的方法是重新设计解决方案以异步接收消息。是的,这有点棘手,但也不算太糟。谢谢你的回答,但正如我提到的,发送两条单独的消息是很重要的,因为在另一个地方,我希望在收到第二条消息之前,只收到第一条消息而不会阻塞
def awaitBothMessages(input: M1, underlyingAActor: ActorRef, system: ActorSystem): Future[(M2, M3)] = {
  val aggregationActor = system.actorOf(Props(new AggregationActor(aActor)))
  (aggregationActor ? input).mapTo[(M2, M3)]
}

val system = ActorSystem("test")
val aActor = system.actorOf(Props(new A), name = "aActor")

// Awaiting the first message only:
val firstMessage = aActor ? M1
val first = Await.result(firstMessage, Duration.Inf)

// Awaiting both messages:
val bothMessages: Future[(M2, M3)] = awaitBothMessages(M1, aActor, system)
val both = Await.result(firstMessage, Duration.Inf)