9

新しい Scala 2.10 futures featureの例を再現しようとしていました。私が使用したコードは次のとおりです。

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 です。

4

3 に答える 3

30

問題は、ワーカー スレッドの 1 つが「Hello future!」を実行する前にメイン スレッドが終了するスタンドアロン プログラムとして実行していることです。println. (新しい futures ライブラリが生成するスレッドはデーモン スレッドです)。

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 future!」と出力することもできます。スレッドスケジュールに応じて、「テストプリント後」の前に。

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

(Awaitオブジェクトは、このような状況に必要なエスケープ ハッチですが、セマンティクスを考慮せずにアプリケーション コード全体で使用すると、実行が遅くなり、並列性が低下する可能性があります。たとえば、コールバックが指定された順序で実行されるようにする必要がある場合のandThenmapメソッドなど、他の代替手段がありますFuture。)

于 2012-05-12T19:03:15.623 に答える
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 つの無意味な Future の実行でビジーであるため、以下の Future は決して実行されません。これが、デフォルトの実行コンテキストに注意する必要がある理由です。複数の (本当に) 長時間実行される Future を扱う場合は、独自の実行コンテキストを指定するのが最善です。

于 2014-04-27T14:33:19.150 に答える
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.")
    }
}
于 2012-05-12T18:06:02.050 に答える