【问题标题】:How to terminate the function when it takes too many time in Scala?在Scala中花费太多时间时如何终止函数?
【发布时间】:2017-06-06 22:33:14
【问题描述】:

最近,我正在学习 Scala 语言。今天我出来一个问题,就是 如何在需要太多时间时终止函数。

例如:

object HelloWorld {
  def main(args: Array[String]) {
    println("Hello, World")
    // How to terminate the sum() function
    // when the time that it takes greater than 2 second?
    val t0 = System.nanoTime : Double
    val total: BigInt = sum(1000000000)
    val t1 = System.nanoTime : Double
    println("Elapsed time " + (t1 - t0) / 1000000.0 + " msecs")

    println(total)

  }

  //Given that sum() is written by others and I cannot change it.
  def sum(k: Int): BigInt = {
    var total: BigInt = 0
    for (i <- 1 to k) {
      total += i
    }
    total
  }
}

上面的scala代码大约需要70s。

【问题讨论】:

    标签: scala


    【解决方案1】:

    使用未来!

    val resultFuture : Future[ReturnType] = Future.apply {
     longComputation
    }
    
    val resultMaybeCut = Await.result(resultFuture, DurationOfChoice)
    

    作为记录,Await.result(awaitable: Awaitable[T], atMost: Duration) :

    • 如果当前线程在等待时被中断,则抛出 InterruptedException
    • 如果在等待指定时间后awaitable 仍未准备好,则抛出 TimeoutException
    • 如果 atMost 是 Duration.Undefined 则抛出 IllegalArgumentException

    警告(感谢@markusthoemmes):

    这样做不会中断底层的未来计算,它只会让你轻松超时! (这可能是也可能不是问题)。 如果我相信Kill or timeout a Future in Scala 2.10 没有超级简单的方法可以真正停止底层计算,所以您可能需要参考此处发布的其他解决方案!

    【讨论】:

    • 我不认为这实际上会停止计算。它退出程序(在这种情况下),但通常不会在未来停止计算。
    • 这是一个非常好的观点,具体取决于用例!我正在寻找有关它的相关文档,如果您有任何链接,请不要犹豫:)
    • 不,Future 的计算不会停止,当时间 (DurationofChoice) 结束时。普通线程可以被中断。
    【解决方案2】:

    现在的计算阻塞了你的主线程。那是您的程序正在运行的线程。在您的计算完成之前,您无法控制在该线程上执行任何操作。

    您可以在单独的 Thread 中运行计算,并在您认为耗时过长时从主线程中终止该 Thread

    注意: 作为 Scala 初学者:线程通常不是 Scala 的方式,但在这种情况下,Scala 提供的抽象(即Futures)并不低水平足以达到你想要达到的目标。请不要将低级的Thread 方式视为您每天都应该做的事情。

    【讨论】:

    • 你能给我一个小演示吗,因为我不知道Thread。谢谢。我已经在工作中使用 Maple 和 MATLAB 大约 5 年了。
    • 可以参考twitter.github.io/scala_school/concurrency.html#Thread。简要介绍 Threads。
    • @markusthoemmes 为什么不是Future 去这里的路?如果时间是在Future块中计算的,那么Future管理应该不会对时间测量产生任何影响(至少,我是这么理解的)。
    【解决方案3】:

    如果您有一个紧密的循环并且只想在某个超时之前不满足条件时想要退出,则不需要线程:

    def sum(k: Int, timeoutMillis: Long): BigInt = {
      val timeoutMillis = System.currentTimeMillis + timeoutMillis
      var total: BigInt = 0
      for (i <- 1 to k) {
        total += i
        if (timeoutMillis < System.currentTimeMillis) 
          throw new RuntimeException("Timed out")
      }
      total
    }
    

    【讨论】:

    • 谢谢。我展示的代码只是我制作的一个简单示例。其实我想找个方法处理一个通用的自定义函数,别人写的或者我不能改的。
    • 很公平,我只是认为考虑到您不需要跳转到线程来限制执行时间是很重要的。
    • 对于 Mathematica 用户,一般我使用Alt + . 来中止Mathematica的计算 内核:)
    • 好一个!比跳到线程更简单的解决方案,你是对的。
    猜你喜欢
    • 1970-01-01
    • 2015-11-28
    • 2016-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多