我刚开始学习Scala的Akka库。我遇到了使用Ask模式从Actor获取响应(就像启动一个线程来完成一些计算并获得结果)。
下面是我的代码,其中我使用了Ask模式,其中Timeout阻止它执行。为什么呢?
import akka.actor._
import akka.routing._
import akka.util.Timeout
import akka.pattern.ask
import java.math.BigInteger
import java.time.LocalDate
import scala.concurrent.duration._
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Success, Failure}
object Main extends App {
val system = ActorSystem("listRetriever")
val workerActor = system.actorOf(Props[Worker], "workerActor")
val listRetriever= new listRetriever
implicit val timeout = Timeout(10 seconds)
val future = workerActor ? new Work(date, listRetriever)
future onComplete {
case Success(result: Result) => println(result.getList())
case Failure(result) => println(result)
}
system.shutdown
}
答案 0 :(得分:6)
如果您查看Timeout
课程的定义,您会发现它需要FiniteDuration
:
case class Timeout(duration: FiniteDuration) extends Product with Serializable
http://doc.akka.io/api/akka/current/#akka.util.Timeout
这是故意的,因此ask
特别不会永远运行。
所以不,你不能在没有有限超时的情况下使用ask
。
答案 1 :(得分:1)
警告,这是一种黑客行为:
这可能不是“最佳实践”,但它是一种有效的方法/解决方法,可以获得无超时“问”。
如果您的原始Work
消息定义如下:
case class Work(params: Params)
然后将Promise
添加到该案例类中,即
case class Work(params: Params, completionPromise: Promise[Result])
创建一种方便的方法,根据Params
:
def doWork(params: Params): Future[Result] = {
val completionPromise = Promise[Result]
val msg = Work(params, completionPromise)
workerActor ! msg
completionPromise.future
}
这仅适用于 IF workerActor
实现知道如何处理completionPromise
。如果工作人员实施不在您的控制之下,则无法执行此操作。
此外,您必须确保worker actor将异常传递给promise。否则,你最终会得到一个永远不会完成的未来。例如,这很糟糕:
def receive = {
case Work(params, completionPromise) =>
val result = doErrorProneOperation(params)
// if an exception is thrown, the following will never happen
completionPromise success result
}
您必须确保考虑例外情况,否则其他内容会显示为挂起:
def receive = {
case Work(params, completionPromise) =>
val result = Try { doErrorProneOperation(params) }
completionPromise complete result
}