2016-01-15 7 views
12

Scalaでは、私はAwaitを使用して、将来の完了を待つことができます。しかし、私がその未来を完了するとコールバックを登録すると、未来が完了するのを待つだけでなく、そのコールバックが終了するまで待つことができますか?ここでスカラ未来のonSuccessコールバックが完了するのを待つ方法を教えてください。

は、問題を説明するための最小限のが、完全なプログラムです:

import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.duration.Duration 
import scala.concurrent.{ Await, Future } 

object Main { 
    def main(args: Array[String]): Unit = { 
    val f: Future[Int] = Future(0) 
    f.onSuccess { case _ => 
     Thread.sleep(10000) 
     println("The program waited patiently for this callback to finish.") 
    } 

    // This waits for `f` to complete but doesn't wait for the callback 
    // to finish running. 
    Await.ready(f, Duration.Inf) 
    } 
} 

私は出力があることを期待:

The program waited patiently for this callback to finish. 

その代わり、出力がありません。プログラムはコールバックが終了する前に終了します。

これは、先にthis questionで回答されている、今後の完了を待っているのと同じ問題ではないことに注意してください。

答えて

16

onSuccessコールバックを使用しないでください。代わりに、Future.map呼び出しで副作用を行います。そうすれば、Awaitを使用する未来の[ユニット]ができます。

import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.duration.Duration 
import scala.concurrent.{ Await, Future } 

object Main { 
    def main(args: Array[String]): Unit = { 
    val f: Future[Int] = Future(0) 
    val f2: Future[Unit] = f.map { x => 
     Thread.sleep(10000) 
     println("The program waited patiently for this callback to finish.") 
    } 

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

成功例(例のように)にのみ副作用を実行する場合は、mapが適切です。障害が発生した場合にも副作用を実行するには、正しい方法を使用してください。 scala-userのRoland Kuhnのpostを参照してください。

また、を入力しないでくださいを使用すると、プロダクションコードのどこかでThread.sleepを使用できます。

+1

あなたが投げている場合は2つの先物を作るにはポイントがありません最初のものの値を離れてください。一つの未来にすべてを走らせるだけかもしれない。 –

+0

これは、指定されたコードに可能な限り近づくことでした。実際のアプリケーションでは、最初の未来はあなたが実際に使用する価値を生むでしょう。 –

+0

'map'と' flatMap'が 'onSuccess'と同じことを達成すれば(なぜならそれらは値を返すことができるので)、なぜAPI内に' onSuccess'があるのでしょうか? 'onFailure'との対称性だけですか?あるいは、 'onSuccess'と' onFailure'の下位レベルの構造体で 'map'と' flatMap'が実装されていますか? –

7
import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.duration.Duration 
import scala.concurrent.{ Await, Future } 
import scala.util._ 

object Main { 
    def main(args: Array[String]): Unit = { 
    val f1: Future[Int] = Future(0) 
    val f2 = f1 andThen { 
     case Success(v) => 
     Thread.sleep(10000) 
     println("The program waited patiently for this callback to finish.") 
     case Failure(e) => 
     println(e) 
    } 

    Await.ready(f1, Duration.Inf) 
    println("F1 is COMPLETED") 
    Await.ready(f2, Duration.Inf) 
    println("F2 is COMPLETED") 
    } 
} 

プリント:

F1 is COMPLETED 
The program waited patiently for this callback to finish. 
F2 is COMPLETED 

約束を使用すると、より明確である:

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

object Main { 
    def main(args: Array[String]): Unit = { 
    val f: Future[Int] = Future(0) 
    val p = Promise[Unit]() 
    p.future.onSuccess { case _ => 
     println("The program waited patiently for this callback to finish.") 
    } 
    f.onSuccess { case _ => 
     Thread.sleep(10000) 
     p.success(()) 
    } 

    Await.ready(f, Duration.Inf) 
    println("F is COMPLETED") 
    Await.ready(p.future, Duration.Inf) 
    println("P is COMPLETED") 
    } 
} 

プリント:

F is COMPLETED 
P is COMPLETED 
The program waited patiently for this callback to finish. 
+1

私は約束を避けることができれば使用してはならない低レベルのAPIだと思います。したがって、andThenを使用した最初の例が優れています。 –

+0

正確に。 Promiseは、 'andThen'が' onComplete'ハンドラの同期を実行するためのものです。 – Suma

+0

'Promise'の例では、' This program ... 'を印刷する前にスリープしても印刷されません。私はこの例題が元の質問と同じ問題を抱えていると思います。 'p.future.onSuccess'を待つものは何もありません。 – nedim

関連する問題