2012-05-12 13 views
9

新しいScala 2.10 futures featureでサンプルを再現しようとしていました。 私が使用したコードは次のとおりです。Scala 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 

私はこの振る舞いを持っている理由の任意のアイデア?私のスカラーコンパイラのバージョンは2.10.0-20120507です。

答えて

28

問題は、あなたが実行していることであることを主なスタンドアロンのプログラムとして、スレッドは、ワーカースレッドの1つが "Hello future!"を実行する前に終了しています。 println。 (新しい先物ライブラリが生成するスレッドはデーモンスレッドです)。それはこんにちは」印刷することができ、

Test print before future 
Test print after future 
Hello future! 

をまたは:

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) 
    } 
} 

これは、印刷することができます。

はまた、将来fが完了するまで待機する(もscala.concurrent中)Awaitオブジェクトを使用することができます未来!"スレッドのスケジュールに応じて、「将来に印刷を試してください」の前に

同様に、あなたは次のよう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、ブロックしています。これはもちろん、メインのアプリケーションスレッドが終了しないことを確認するのに理にかなっていますが、通常は別途必要な場合を除いては使用しないでください。

(これらのような状況では、オブジェクトは必要なエスケープハッチですが、セマンティクスを気にせずにアプリケーションコード全体で使用すると、パラレル実行が遅くなる可能性があります。例えば、FutureandThenmapのメソッドのような他の選択肢があります。)

+0

ご存知ですか?私は、あなたがgoroutinesを扱っているときに、これがまさに同じように起こっていると考えました。メインブロックを閉じる前に、チャンネルを使ってゴルーチンから送られたメッセージを待っていました。 –

+0

@Heather複数の未来を待つことは可能でしょうか? – 66CLSjY

1

ここでの問題はタイミングだと思います。おそらくあなたの将来のコードは、別々のデーモンスレッドで実行されています。私はアプリケーションが非常に速く終了し、このデーモンスレッドが適切に実行するのに十分な時間がないと思う(アプリケーションはデーモンスレッドが終了するのを待たない)。しかし、これはシステムにも非常に依存します。私のために、それは印刷します:

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が最適です。

関連する問題