2014-01-30 24 views
1

我正在使用scala dispatch(0.11.0)庫向遠程服務器發送HTTP GET請求。我想在執行請求之後的代碼之前等待響應。我該如何等待scala dispatch(0.11.0)http get請求才能完成?

我的要求是形式:

val req = :/("myurl.com") <:< myheaders OK as.Response(identity) 

如果我寫:

val future = http(req) 
future() 
var res: String = null 
future onComplete { 
    case Success(r) => res = r.getResponseBody 
    case _ => println("KO") 
} 
println(res) 

我得到空。 這也是如此,如果我寫的:

val future = http(req) 
var res: String = null 
while (!future.isCompleted) { 
    Thread.sleep(1000) 
} 
future onComplete { 
    case Success(r) => res = r.getResponseBody 
    case _ => println("KO") 
} 
println(res) 

但與下面的代碼:

val future = http(req) 
var res: String = null 
future onComplete { 
    case Success(r) => res = r.getResponseBody 
    case _ => println("KO") 
} 
while (!future.isCompleted) { 
    Thread.sleep(1000) 
} 
println(res) 

我得到預期的迴應。

有人明白嗎? 在我看來,調用Thread.sleep不是一件好事,有人可以給我一個關於如何正確處理這個問題的提示嗎?

編輯:@Randal Schulz感謝您的幫助,但是當您發表評論時,我無法驗證您的答案。

由於我的問題是等待(直到我得到一個有效的HTTP GET請求響應),我認爲一個令人滿意的方式是使用Await.result。我從我的代碼中刪除了副作用。我用選項方法來處理未來的失敗(因爲我只對成功感興趣),並且我用經典的方式處理超時異常。

我想我能做到這一點的麥片mentionned,留在未來,但我需要更多的練習......

+1

使用'Await.ready'(返回'Future'本身)或'Await.result'(返回由'Future'計算出的值),併爲可能的異常做準備,因爲「Future」超時或失敗'本身。 –

+0

好的,謝謝你指出這些,因爲我沒有意識到Future不是一個派遣概念。儘管如此,使用Await.result,我得到的結果與以前相同:/ – ygu

+0

您顯示了三次嘗試(其中只有一次嘗試產生了「預期響應」)。當你說你得到「和以前一樣的結果」時,你指的是哪一個?「 –

回答

-2

我終於寫什麼,我想利用期貨:

def loop(): Future[String] = { 
    val future = http(req).option 
    future flatMap ((x: Option[Response]) => x match { 
     case Some(rep) => rep.getResponseBody 
     case None => loop() 
    } 
} 

現在我可以使用這個功能的結果沒有明確地等待響應來。

+0

你的代碼無非是浪費CPU時間...如果你真的想要同步,你應該使用例如'Await.result'。 –

3

TL; DR

我可以給你在工作的最好的建議異步工作流程是Future保留在Future中。

回答

的問題是,你不知道當Future將完成,所以如果你想使用一個異步的過程,你將不得不以異步方式來寫。您所編寫的代碼永遠不會停止或阻止您創建的Future,因此只要創建Future的分鐘並將其交給另一個線程,當前線程就可以自由地評估變量res

因此,最到位的你在一個流程做什麼樣如下:

myFuture map (func1) map (func2) map (func3) onComplete{ 
    case Success(value) => println(value.getResponseBody) 
    case _ => println('KO') 
} 

不要試圖通過副作用來訪問像你。

如果你很聰明,你有幾個Future您可以撰寫他們:

val f1 = myFuture map(func1) 
val f2 = myOtherFuture map(func2) map (func3) 

val f3 = for{ 
    v1 <- f1 
    v2 <- f2 
} yield functionTakingBoth(v1, v2) 

f3 onComplete{ 
    //and do stuff here 
} 
+0

根據您正在使用的其他庫(常規的,不基於nio的I/O,DNS,DBMS交互等),完全避免阻塞通常是不可行的。在阻止操作或等待「未來」完成時,我從來沒有發現簡單地說「不這樣做」就足夠了。 –

+0

好吧,我錯了......如果我理解的很好,我的所有程序都應該在Future中,因爲它取決於第一條指令,它是一個異步指令(一個HTTP GET請求),對吧? – ygu

+1

@RandallSchulz通常,我使用非異步方式編寫代碼,並將其包裝在「Future」中,以便系統不會自上而下綁定到「Future」。而且,爲了提高性能,如果可能的話,我將CPU密集型和I/O密集型事物分解到不同的線程池中。就是說,本質上,「未來」的美麗。你可以包裝任何東西,它永遠不需要知道。 – wheaties