2012-05-12 33 views
9

我試圖重現新斯卡拉2.10 futures feature的例子。 我使用的代碼是:可能的錯誤在斯卡拉2.10:期貨市場不運行

import scala.concurrent.Future 
import scala.concurrent.future 

object Test { 
    def main(args: Array[String]) { 
    println("Test print before future") 
    val s = "Hello" 
    val f = future {s + " future!"} 
    f onSuccess {case v => println(v)} 
    println("Test print after future") 
    } 
} 

除了打印:

Test print before future 
Hello future! 
Test print after future 

它只是打印:

Test print before future 
Test print after future 

爲什麼我有這樣的行爲的任何想法?我的版本的scala編譯器是2.10.0-20120507。

回答

28

的問題是,您執行的是作爲一個獨立的程序,其主要線程在其中一個工作線程執行「Hello future!」之前終止。 println。 (新期貨庫產生的線程是守護進程線程)。

您還可以使用Await對象(也scala.concurrent)等到未來f完成:

import scala.concurrent._ 
import scala.concurrent.util._ 

object Test { 
    def main(args: Array[String]) { 
    println("Test print before future") 

    val s = "Hello" 
    val f = future {s + " future!"} 
    f onSuccess {case v => println(v)} 
    println("Test print after future") 

    Await.ready(f, Duration.Inf) 
    } 
} 

這可以打印:

Test print before future 
Test print after future 
Hello future! 

或者,它可以打印「Hello未來!」根據線程安排,在「未來測試打印」之前。

同樣,你可以強制主線程等待,直到f在最後println前完成如下:

import scala.concurrent._ 
import scala.concurrent.util._ 

object Test { 
    def main(args: Array[String]) { 
    println("Test print before future") 

    val s = "Hello" 
    val f = future {s + " future!"} 
    f onSuccess {case v => println(v)} 

    Await.ready(f, Duration.Inf)   

    println("Test print after future") 
    } 
} 

這將打印:

Test print before future 
Hello future! 
Test print after future 

但是,請注意,當您使用Await,你擋住了。這當然是有意義的,以確保您的主應用程序線程不會終止,但通常不應使用,除非必要否則。對於像這樣的情況來說,對象是一個必要的逃生方法,但是在整個應用程序代碼中使用它而不關心它的語義會導致更慢,更不平行的執行。如果你需要確保回調在一些例如,還有其他替代方法,例如Future上的andThenmap方法。)

+0

你知道嗎?我想過這個問題,因爲在處理goroutines時,其原因完全相同:在關閉主塊之前使用通道等待goroutines發送的消息。 –

+0

@ Heather是否有可能等待多個未來? – 66CLSjY

1

我認爲這裏的問題是時機。很可能你的將來的代碼運行在單獨的deamon線程中。我認爲該應用程序速度非常快,而且這個deamon線程沒有足夠的時間來正確執行(應用程序不會等待deamon線程完成)。但是這也是非常依賴系統的行爲。對我來說,它打印:

Test print before future 
Test print after future 
Hello future! 

然後退出(我正在使用Scala 2.10.0-M3)。你可以嘗試,以測試它下面的 - 只是把主要的執行線程睡眠幾秒鐘,看看是否Hello future!打印:

import scala.concurrent.Future 
import scala.concurrent.future 

object Test { 
    def main(args: Array[String]) { 
     println("Test print before future") 

     val s = "Hello" 
     val f = future {s + " future!"} 
     f onSuccess {case v => println(v)} 

     println("Test print after future") 

     Thread.sleep(3000) 
     println("Test print at the end.") 
    } 
} 
1

我只想補充一點,期貨沒有運行還有另一種可能性:達到線程池限制。

你的情況,它可能只是一個時間問題,因爲其他人指出,但作爲未來的參考考慮這個例子:

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


object FutureDebug { 
    def main(args: Array[String]) { 

    for (i <- Range(0, 4)) { 
     future { 
     while (true) { 
      Thread.sleep(1000) 
      println("I'm doing stupid things in a future") 
     } 
     } 
    } 

    println("(1) reached? yes") 
    val fut = future { 
     for (i <- Range(0, 1000)) { 
     println("never reached " + i) 
     } 
     3.14 
    }  
    println("(2) reached? yes") 
    Await.result(fut, Duration.Inf) 
    println("(3) reached? no") 
    } 
} 

在我的機器默認的全局執行上下文剛剛4個線程。由於工作線程忙於執行4種非感知期貨,因此下面的未來將永遠不會運行。這就是爲什麼人們應該小心處理默認執行上下文,並且最好在處理多個(真正)長期運行的期貨時使用specify one's own execution context