Scala如何使用akka actor有效地处理超时操作

Posted

技术标签:

【中文标题】Scala如何使用akka actor有效地处理超时操作【英文标题】:Scala how to use akka actors to handle a timing out operation efficiently 【发布时间】:2013-07-11 11:46:53 【问题描述】:

我目前正在使用 Rhino 在一个安静的服务中评估 javascript 脚本。我希望有一个评估超时。 我创建了一个模拟示例演员(使用 scala 2.10 akka 演员)。

case class Evaluate(expression: String)

class RhinoActor extends Actor 

  override def preStart() =  println("Start context'"); super.preStart()

  def receive = 
    case Evaluate(expression) ⇒ 
      Thread.sleep(100)
      sender ! "complete"
    
  

  override def postStop() =  println("Stop context'"); super.postStop()

现在我运行如下使用这个actor:

  def run 
    val t = System.currentTimeMillis()
    val system = ActorSystem("MySystem")

    val actor = system.actorOf(Props[RhinoActor])

    implicit val timeout = Timeout(50 milliseconds)
    val future = (actor ? Evaluate("10 + 50")).mapTo[String]

    val result = Try(Await.result(future, Duration.Inf))

    println(System.currentTimeMillis() - t)
    println(result)
    actor ! PoisonPill

    system.shutdown()
  

在这样一个可能同时有请求的闭包中使用 ActorSystem 是否明智?

我应该将 ActorSystem 设为全局吗,在这种情况下可以吗?

有没有更合适的替代方法?

编辑:我认为我需要直接使用期货,但我需要 preStart 和 postStop。目前正在调查。 编辑:似乎你没有得到期货的那些钩子。

【问题讨论】:

【参考方案1】:

我会尽力为您解答一些问题。

首先,ActorSystem 是一个非常重的构造。您不应该为需要参与者的每个请求创建一个。您应该全局创建一个,然后使用该单个实例来生成您的演员(在run 中您将不再需要system.shutdown())。我相信这涵盖了您的前两个问题。

您在这里使用演员执行 javascript 的方法对我来说似乎是合理的。但是,您可能希望在Router 后面汇集一堆RhinoActors,而不是每个请求都启动一个actor,每个实例都有自己的rhino 引擎,该引擎将在preStart 期间设置。这样做将消除每个请求的犀牛初始化成本,加快你的 js 评估。只要确保你的游泳池大小合适。此外,如果您采用这种方法,则无需为每个请求发送 PoisonPill 消息。

您可能还想查看非阻塞回调 onCompleteonSuccessonFailure,而不是使用阻塞 Await。这些回调也尊重超时,并且比阻塞更高的吞吐量更可取。只要上游等待此响应的任何方式都可以处理异步性(即支持异步的 Web 请求),那么我建议走这条路线。

最后要记住的是,即使代码会在超时后返回给调用者,如果参与者尚未响应,参与者仍会继续处理该消息(执行评估)。它不会仅仅因为呼叫者超时而停止并转到下一条消息。只是想澄清一下,以防万一。

编辑

针对您关于停止长时间执行的评论,有一些与 Akka 相关的事情需要首先考虑。您可以调用停止actor,发送KillPosionPill,但如果处理当前正在处理的消息,这些都不会停止。他们只是阻止它接收新消息。在您的情况下,对于 Rhino,如果无限脚本执行是可能的,那么我建议在 Rhino 本身内处理这个问题。我会深入研究这篇文章 (Stopping the Rhino Engine in middle of execution) 上的答案,并在 Actor 中设置您的 Rhino 引擎,使其在执行时间过长时会自行停止。该失败将踢出到主管(如果被池化)并导致该池化实例重新启动,这将在preStart 中启动一个新的 Rhino。这可能是处理长时间运行脚本可能性的最佳方法。

【讨论】:

谢谢,这很有帮助。什么是迫使演员停止的最佳方式,因为我不希望我的线程建立处理潜在的无限脚本? @JPullar,围绕您的评论在我的回答中添加了更多信息

以上是关于Scala如何使用akka actor有效地处理超时操作的主要内容,如果未能解决你的问题,请参考以下文章

Scala笔记整理:Actor和AKKA

Scala笔记整理:Actor和AKKA

[scala] akka actor编程

Scala框架Akka学习

与 Scala / Akka Actor 相比,Java 线程有多重?

Scala并发框架Akka原理详解