是否有标准的Scala函数用于运行具有超时的块?

时间:2011-06-03 13:32:46

标签: scala concurrency

我需要调用可能会或不会及时返回结果的服务。我希望能够写

val result = runWithTimeout(5000, valReturnedOnTimeout) { service.fetch }

是否有标准功能可以完成这项工作 - 比如Ruby的timeout

6 个答案:

答案 0 :(得分:7)

归功于其他答案 - 在没有任何标准库功能的情况下,我已经走下了期货路线。

  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent._
  import scala.concurrent.duration._

  def runWithTimeout[T](timeoutMs: Long)(f: => T) : Option[T] = {
    Await.result(Future(f), timeoutMs milliseconds).asInstanceOf[Option[T]]
  }

  def runWithTimeout[T](timeoutMs: Long, default: T)(f: => T) : T = {
    runWithTimeout(timeoutMs)(f).getOrElse(default)
  }

那样

  @Test def test {
    runWithTimeout(50) { "result" } should equal (Some("result"))
    runWithTimeout(50) { Thread.sleep(100); "result" } should equal (None)
    runWithTimeout(50, "no result") { "result" } should equal ("result")
    runWithTimeout(50, "no result") { Thread.sleep(100); "result" } should equal("no result")
  }

对于这是否是一个很好的Scala风格我感激不尽!

答案 1 :(得分:5)

你可以使用未来

import scala.actors.Futures._  

val myfuture = 
    future {
     Thread.sleep(5000)
     println("<future>")
     "future "
 }

 awaitAll(300,myfuture ) foreach println _   

但是也看看Circuit Breaker for Scala这是一个实现 Circuit Breaker Pattern。基本上,它允许您控制超时以及在访问外部资源时发生故障会发生什么

用法在Scala中看起来像这样(来自自述文件):

. . .
addCircuitBreaker("test", CircuitBreakerConfiguration(timeout=100,failureThreshold=10))
. . .


class Test extends UsingCircuitBreaker {
  def myMethodWorkingFine = {
    withCircuitBreaker("test") {
      . . .
    }
  }

  def myMethodDoingWrong = {
    withCircuitBreaker("test") {
      require(false,"FUBAR!!!")
    }
  }
}

答案 2 :(得分:2)

可能Futures及其alarm可以解决问题吗?

答案 3 :(得分:2)

尚未提及的东西是 awaitEither ,这是actor包的Futures对象上的一个方法。 awaitEither返回完成的一对期货中的第一个的结果,所以例如可以使用这样的东西:

awaitEither(future{task}, alarm(timeoutPeriod))

然后按照建议的方法打扮:

def runWithTimeout[T](timeoutPeriod: Int, timeoutValue: T)(task: => T) = {
  awaitEither(future{task}, alarm(timeoutPeriod)) match {case () => timeoutValue case x => x}
}

警告返回可分配给任何类型的val的单位,以便awaitEither返回可以进行模式匹配的内容。

答案 4 :(得分:1)

您可以在新线程中启动它,然后等待它完成Thread.join。如果将参数传递给join,它最多等待很多毫秒。

val t = new Thread {
  override def run() {
    //...
  }
}
t.start()
t.join(5000)

答案 5 :(得分:0)

上面的帖子

  import scala.concurrent.ExecutionContext.Implicits.global   import
 scala.concurrent._   import scala.concurrent.duration._

   def runWithTimeout[T](timeoutMs: Long)(f: => T) : Option[T] = {
     Await.result(Future(f), timeoutMs milliseconds).asInstanceOf[Option[T]]   }

   def runWithTimeout[T](timeoutMs: Long, default: T)(f: => T) : T = {
     runWithTimeout(timeoutMs)(f).getOrElse(default)   }

在Scala 2.11上对我不起作用。

以下修改版本对我有用:

  def runWithTimeout[T](timeout: Long)(f: => T): Option[T] = {
    Option.apply(Await.result(Future(f), timeout seconds))
  }