1

Recently, I am learning the Scala language. Today I come out a question, that is, how to terminate a function when it takes too many time.

For example:

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
  }
}

enter image description here

The above scala code takes about 70s.

xyz
  • 413
  • 2
  • 19

3 Answers3

5

Use Future(s) !

val resultFuture : Future[ReturnType] = Future.apply {
 longComputation
}

val resultMaybeCut = Await.result(resultFuture, DurationOfChoice)

For the record, Await.result(awaitable: Awaitable[T], atMost: Duration) :

  • throws InterruptedException if the current thread is interrupted while waiting
  • throws TimeoutException if after waiting for the specified time awaitable is still not ready
  • throws IllegalArgumentException if atMost is Duration.Undefined

Warning (thanks @markusthoemmes):

Doing this doesn't interrupt the underlying future computation, it just let you easily timeout on it ! (which may or may not be a problem). If I'm to believe Kill or timeout a Future in Scala 2.10 there's no super simple way to actually stop the underlying computation, so you may want to refer to the other solutions posted here !

C4stor
  • 8,355
  • 6
  • 29
  • 47
  • I don't think this actually stops the computation. It exits the program (in this case) but won't generally stop the computation in the future. – markusthoemmes Jun 06 '17 at 14:05
  • That's a very good point, depending on the use case ! I'm looking for relevant documentation about it, please don't hesitate to link me if you have any :) – C4stor Jun 06 '17 at 14:28
  • No, the calculation of the Future won't stop, when time (DurationofChoice) is over. Plain Threads can be interrupted though. – Hartmut Pfarr Apr 03 '22 at 21:01
2

The computation as it is now blocks your main thread. That is the thread your program is running in. You don't have control to execute anything on that thread until your computation is finished.

You can run the computation in a seperate Thread and kill that Thread from your main thread once you think it's taking too long.

Note: As you're a Scala beginner: Threads are usually not the way to go in Scala, but in this case the abstractions provided by Scala (namely Futures) are not low level enough for what you're trying to achieve. Please don't consider the low-level Thread way as something you should be doing every day.

markusthoemmes
  • 3,080
  • 14
  • 23
  • Could you give me a small demo because I don't know the `Thread`. Thanks. I have been using Maple and MATLAB in my work for about 5 years. – xyz Jun 06 '17 at 13:12
  • You can refer to https://twitter.github.io/scala_school/concurrency.html#Thread. For a short introduction into Threads. – markusthoemmes Jun 06 '17 at 13:17
  • @markusthoemmes why isn't `Future` the way to go here? If the time is calculated in the `Future` block, the `Future` management should not have any impact on the time measurement (at least, that's how I understand it). – Cyrille Corpet Jun 06 '17 at 13:26
2

Threads are not strictly required for this if you have a tight loop and just want to exit if the condition is not met before a certain timeout:

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
}
SimonC
  • 6,590
  • 1
  • 23
  • 40
  • Thanks. The code I showed is just a simple example I made. In fact, I would like to find a method to deal with a general user-defined function, which is writen by others or I **cannot** change it. – xyz Jun 06 '17 at 13:47
  • Fair enough, I just thought it was important to consider that you don't *need* to jump to threads to constrain execution times. – SimonC Jun 06 '17 at 13:48
  • For a ***Mathematica*** user, generally, I used `Alt + . `to abort the calculation of ***Mathematica*** kernel :) – xyz Jun 06 '17 at 13:50
  • Good one! Simpler solution than jumping to Threads, you're right. – markusthoemmes Jun 06 '17 at 14:06