2011-06-03 70 views
6

我需要调用一个可能返回或不返回及时结果的服务。我希望能写是否有一个标准的Scala函数用于运行带超时的块?

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

有没有一个标准功能,将做的工作 - 像Ruby的timeout

+0

是的,我知道使用Actor可以解决这个问题,但对于这样一个简单的问题似乎过度。 – 2011-06-03 13:33:35

+0

相关http://stackoverflow.com/q/5797666/132374 – 2013-10-30 03:07:53

回答

6

以信誉其他的答案 - 在没有任何标准库函数,我已经走下了期货路线。

import scala.concurrent._ 
    import scala.concurrent.duration._ 

    def runWithTimeout[T](timeoutMs: Long)(f: => T) : Option[T] = { 
    Await.result(Future(f), timeMins 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") 
    } 

我会的任何反馈表示感谢,这是否是一个很好的斯卡拉风格!

+0

我已经扩展了这个来处理异常在http://stackoverflow.com/questions/6229778 – 2011-06-06 08:10:58

1

您可以在一个新的线程中启动它,然后等待它完成Thread.join。如果你传递一个参数来加入,它最多等待几毫秒。

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

谢谢,我也可以使用Executors框架。但我在检查我是不是缺少内置或惯用的东西。 – 2011-06-03 13:46:52

2

可能Futures和它的alarm有窍门吗?

+0

我还没有看到,谢谢,这当然是一种实现该功能的方法 - 如果它不存在的话。 – 2011-06-03 14:10:20

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一个实现。基本上,它可以让你控制超时,如果发生故障访问外部资源

使用看起来像这样在斯卡拉(自述)会发生什么:

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


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

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

我喜欢断路器,但我想标准库中没有任何东西。我会尽量写一些基于期货的东西来保持简单。 – 2011-06-03 15:06:17

+0

请注意,未来阻塞线程。 http://stackoverflow.com/q/5646879/203968因此,多次呼叫您的客户端可能会导致您的线程挨饿。因此断路器。当你认为通话不可能工作时,你可以“打破电路” – oluies 2011-06-03 15:39:32

+0

是的,我将不得不考虑这一点,因为通话在我的网络层,所以我可以每个浏览器都有一个。我可能必须让浏览器轮询并最终使用Executors。 – 2011-06-03 15:48:18

2

还没有提到的东西是等待,这是一个关于actors包的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} 
} 

报警返回可赋值给Any类型的val的单元,因此awaitEither返回可与模式匹配的东西。

+0

我认为,当@ pr1001指出'报警',但认为我们可能会最终开始另一个线程的报警 - 这似乎有点矫枉过正。它确实使一个很好的短暂的表达。 – 2011-06-03 21:36:19

相关问题