如何在用Scala编写的Actor系统中从未来获取数据?

如何在用Scala编写的Actor系统中从未来获取数据?,scala,akka,actor,Scala,Akka,Actor,我有一个Actor say process命令Actor,其接收方法实现如下: class ProcessTheCommand extends Actor { def receive = { case obj: DataObject => val f1 = OneActor ? obj val f2 = SecondActor ? obj // val result= resultFromf1 + resultFromf2

我有一个Actor say process命令Actor,其接收方法实现如下:

class ProcessTheCommand extends Actor {
   def receive = {
     case obj: DataObject => 
       val f1 = OneActor ? obj
       val f2 = SecondActor ? obj
       // val result= resultFromf1 + resultFromf2
       // do something using the result
   }
}
我的问题:如何从两个期货中获取数据?


一种方法是使用
wait
,但这不是最佳做法。建议?

问题分为两部分。第一个是如何提取两个期货并将它们相加,第二个是如何在阿克卡处理这些期货的结果

撰写期货: 有两种方法。我假设未来的结果是一样的。一种是用于理解:

val firstFuture: Future[Int] = ???
val secondFuture: Future[Int] = ???
val result: Future[Int] = for {
  first <- firstFuture
  second <- secondFuture
} yield first + second
另一种是
zip
map
(谢谢@ViktorKlang):

或者使用Scala 2.12
zipWith

val result: Future[Int] = firstFuture.zipWith(secondFuture) {
  case (first, second) => first + second
}
提取参与者内部的值: 唯一缺少的是我们如何得到累积的结果。Akka中的模式是将结果通过管道传输到您自己的
Receive
,因为我们永远不想阻止方法调用,我们真正想要的是在回调完成后调用回调,这正是
pipeTo
将要做的

我们将创建一个自定义案例类,该类封装结果:

case class AccumulatedResult(result: Int)
并将其添加到
Receive

import akka.pattern.pipe
override def receive: Receive = {
  case obj: DataObject => 
    val firstFuture = OneActor ? obj
    val secondFuture = SecondActor ? obj
    firstFuture
     .zip(secondFuture)
     .map { case (first, second) => AccumulatedResult(first + second) }
     .pipeTo(self)

  case AccumulatedResult(res) => println(res)
}

这样做的好处是,一旦将来完成,消息的处理将作为参与者的流处理逻辑的一部分继续进行。

receive
内阻塞方法是一个很大的禁忌,因此永远不要使用wait inside
receive
,否则您将耗尽资源。所有消息处理只在几个工作线程中进行

要处理两个未来,您可能需要使用它们的一元属性:

val result: Future[Int] = firstFuture.flatMap { firstValue => 
   secondFuture.flatMap { secondValue => 
      firstValue + secondValue
   }
}
或同样的事情,通过理解:

val result: Future[Int] = for {
  fistValue <- firstFuture
  secondValue <- secondFuture
} yield firstValue + secondValue

另请参见:

或zip+地图或2.12:zipWith@ViktorKlang谢谢你,维克多。补充。
val result: Future[Int] = firstFuture.flatMap { firstValue => 
   secondFuture.flatMap { secondValue => 
      firstValue + secondValue
   }
}
val result: Future[Int] = for {
  fistValue <- firstFuture
  secondValue <- secondFuture
} yield firstValue + secondValue
import akka.pattern.pipe
val resultFuture: Future[Int] = for {
  fistValue <- firstFuture
  secondValue <- secondFuture
} yield firstValue + secondValue
resultFuture pipeTo sender() // sends result to the sender when future is completed