如何在用Scala编写的Actor系统中从未来获取数据?
我有一个Actor say process命令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
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.12zipWith
:
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 insidereceive
,否则您将耗尽资源。所有消息处理只在几个工作线程中进行
要处理两个未来,您可能需要使用它们的一元属性:
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