我需要调用可能会或不会及时返回结果的服务。我希望能够写
val result = runWithTimeout(5000, valReturnedOnTimeout) { service.fetch }
是否有标准功能可以完成这项工作 - 比如Ruby的timeout?
答案 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))
}