2011-06-03 55 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

相關問題