考虑以下使用Akka计算阶乘的Scala代码。我不知道如何获得输出。
import scala.annotation.tailrec
import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
import scala.concurrent.Await
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
case class GetResult()
class FactorialCalculator extends Actor {
def receive = {
case num: Int => sender ! (num, factor(num))
}
private def factor(num: Int) = factorTail(num, 1)
@tailrec private def factorTail(num: Int, acc: BigInt): BigInt = {
(num, acc) match {
case (0, a) => a
case (n, a) => factorTail(n - 1, n * a)
}
}
}
class FactorialCollector(factorials: List[Int]) extends Actor with ActorLogging {
var list: List[BigInt] = Nil
var size = factorials.size
for (num <- factorials) {
context.actorOf(Props(new FactorialCalculator)) ! num
}
def receive = {
case (num: Int, fac: BigInt) => {
log.info(s"factorial for $num is $fac")
list = fac :: list
size -= 1
if (size == 0) {
log.info(list.toString)
context.system.shutdown()
}
}
case GetResult => sender ! list
}
}
class Factorial(factorials: List[Int]) {
val system = ActorSystem("factorial")
val collector = system.actorOf(Props(new FactorialCollector(factorials)), "collector")
implicit val timeout = Timeout(10 seconds)
val future = collector ? GetResult
val result = Await.result(future, timeout.duration)
system.awaitTermination()
}
var x = new Factorial(List(50, 18, 32, 28, 22, 42, 55, 48))
结果存储在课程list
中计算的变量FactorialCollector
中,但x.result
会返回空的list
。
答案 0 :(得分:1)
首先,您不应该使用表单context.actorOf(Props(new FactorialCalculator))
,但是:
context.actorOf(Props[FactorialCalculator])
source
其次,您可以将messege发送到FactorialCollector for anwser,例如:
def receive = {
....
case GiveMeResult => sender ! list
....
}
或者不是在列表中给出要在构造函数中计算的整数,而是可以通过ask方法将它发送给Collector。然后你最后得到计算结果的未来。
答案 1 :(得分:0)
您将GetResult消息发送到FactorialCollector BEFORE收集器收到FactorialCalculators的所有结果
相反
for (num <- factorials) {
context.actorOf(Props(new FactorialCalculator)) ! num
}
你需要
val res = Await.result(Future.traverse(factorials)(context.actorOf(Props(new FactorialCalculator)) ? _), timeout)
但Await很难看 - 不要和akka一起使用:)。
阅读stash / unstashAll和context.become(..)