如何等待 Scala 未来的 onSuccess 回调完成?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34808024/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I wait for a Scala future's onSuccess callback to complete?
提问by Dan Li
In Scala, I can use Awaitto wait for a future to complete. However, if I have registered a callback to run upon completion of that future, how can I wait not only for the future to complete but also for that callback to finish?
在 Scala 中,我可以使用Await等待未来完成。但是,如果我注册了一个回调以在该未来完成时运行,我如何不仅等待未来完成而且还等待该回调完成?
Here is a minimal but complete program to illustrate the problem:
这是一个最小但完整的程序来说明问题:
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)
}
}
I expect the output to be:
我希望输出是:
The program waited patiently for this callback to finish.
Instead, there is no output; the program exits before the callback finishes.
相反,没有输出;程序在回调完成之前退出。
Please note that this is not the same problem as waiting for a future to complete, which has been answered previously at this question.
请注意,这与等待未来完成不同的问题,之前已在此问题中回答过。
回答by Rüdiger Klaehn
Don't use an onSuccess callback, but instead do the side effect in a Future.map call. That way, you have a Future[Unit] to use Await on.
不要使用 onSuccess 回调,而是在 Future.map 调用中执行副作用。这样,你就有了一个 Future[Unit] 来使用 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)
}
}
Note that if you want to execute a side effect only in case of success (like in your example), map is appropriate. If you want to execute a side effect also in case of failure, andThen is the right method to use. See this postfrom Roland Kuhn on scala-user.
请注意,如果您只想在成功的情况下执行副作用(如您的示例),则 map 是合适的。如果你想在失败的情况下也执行副作用,那么是正确的使用方法。请参阅Roland Kuhn 在 scala-user 上的这篇文章。
Also, please don'tuse Thread.sleep anywhere near production code.
另外,请不要在生产代码附近的任何地方使用 Thread.sleep。
回答by y?s??la
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")
}
}
prints:
印刷:
F1 is COMPLETED
The program waited patiently for this callback to finish.
F2 is COMPLETED
Using promises is even more clear:
使用 promise 就更清楚了:
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")
}
}
prints:
印刷:
F is COMPLETED
P is COMPLETED
The program waited patiently for this callback to finish.

