[英]How to get data from a future in an Actor System written in Scala?
I have an Actor say ProcessTheCommand actor which has a receive method implemented as below: 我有一个演员说ProcessTheCommand演员,它具有如下实现的接收方法:
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
}
}
My problem: How do i get the data out of the two futures? 我的问题: 如何从两个期货中获取数据?
One way to do it is to use await
but that is not the best practice. 一种方法是使用
await
但这不是最佳实践。 Suggestions? 有什么建议吗?
There are two parts to the question. 这个问题有两个部分。 The first is how to extract two futures and add them together, and the second one is how we process the result of these futures in Akka.
第一个是如何提取两个期货并将它们加在一起,第二个是我们如何在Akka中处理这些期货的结果。
There a couple of ways. 有几种方法。 I'm assuming the results of the futures is the same.
我假设期货的结果是相同的。 One would be using for comprehension:
一个会用于理解:
val firstFuture: Future[Int] = ???
val secondFuture: Future[Int] = ???
val result: Future[Int] = for {
first <- firstFuture
second <- secondFuture
} yield first + second
Another option would be to use Future.sequence
: 另一种选择是使用
Future.sequence
:
val firstFuture: Future[Int] = ???
val secondFuture: Future[Int] = ???
val result: Future[Int] = Future
.sequence(Seq(firstFuture, secondFuture))
.map {
results => results.sum
}
Another would be zip
with map
(thanks @ViktorKlang): 另一个将是带有
map
zip
(感谢@ViktorKlang):
firstFuture
.zip(secondFuture)
.map { case (first, second) => first + second }
Or with Scala 2.12 zipWith
: 或与Scala 2.12
zipWith
:
val result: Future[Int] = firstFuture.zipWith(secondFuture) {
case (first, second) => first + second
}
The only missing piece is how we get the accumulated result. 唯一缺少的部分是我们如何获得累积结果。 The pattern in Akka is to pipe the result to your own
Receive
, since we never want to block on the method call, what we actually want is the future to invoke a callback once it completes, which is exactly what pipeTo
will do. Akka中的模式是将结果通过管道传递到您自己的
Receive
,因为我们从不希望在方法调用上阻塞,所以我们真正想要的是将来在完成回调后调用回调,这正是pipeTo
会做的。
We'll create a custom case class which encapsulates the result: 我们将创建一个自定义案例类,其中封装了结果:
case class AccumulatedResult(result: Int)
And add it in Receive
: 并将其添加到
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)
}
The nice thing about this is that once the future completes the handling of the message will continue as part of the flow handling logic of the actor. 这样做的好处是,一旦将来完成,消息的处理将继续作为参与者的流处理逻辑的一部分。
Blocking inside receive
method is a big NO, so never use await inside receive
, otherwise you'll starve on resources. 在
receive
方法内部阻塞是一个很大的问题,因此不要在receive
内部使用await,否则您将饿死资源。 All message processing happens in just a couple of worker threads. 所有消息处理仅在几个工作线程中进行。
To handle two futures, you might want to use their monadic properties: 要处理两个期货,您可能需要使用它们的单子属性:
val result: Future[Int] = firstFuture.flatMap { firstValue =>
secondFuture.flatMap { secondValue =>
firstValue + secondValue
}
}
Or same thing via for-comprehension: 或通过理解理解相同的东西:
val result: Future[Int] = for {
fistValue <- firstFuture
secondValue <- secondFuture
} yield firstValue + secondValue
However, this is not what you usually want in actors, because you still get a Future and would need to block until it's completed. 但是,这不是演员通常需要的,因为您仍然可以获得Future,并且需要阻塞直到完成。 What you usually want is to pass the value to the caller or the next actor.
通常,您希望将值传递给调用方或下一个参与者。 And for this you can use
pipe
pattern: 为此,您可以使用
pipe
模式:
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
See also: Futures in Akka 另请参阅: Akka期货
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.