我如何等待Scala的未来';s onSuccess回调是否要完成?
在Scala中,我可以使用我如何等待Scala的未来';s onSuccess回调是否要完成?,scala,concurrency,future,Scala,Concurrency,Future,在Scala中,我可以使用wait来等待未来的完成。但是,如果我已经注册了一个回调,在该未来完成时运行,那么我如何不仅等待未来完成,而且等待回调完成呢 下面是一个最小但完整的程序来说明问题: import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration.Duration import scala.concurrent.{ Await, Future } object Main
wait
来等待未来的完成。但是,如果我已经注册了一个回调,在该未来完成时运行,那么我如何不仅等待未来完成,而且等待回调完成呢
下面是一个最小但完整的程序来说明问题:
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.
相反,没有产出;程序在回调完成之前退出
请注意,这与等待future完成的问题不同,前面的回答是。不要使用onSuccess回调,而是在future.map调用中执行副作用。这样,您就有了一个可供使用的未来[单元]
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用户Roland Kuhn的文章
另外,请不要在生产代码附近使用Thread.sleep
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
F is COMPLETED
P is COMPLETED
The program waited patiently for this callback to finish.
使用承诺更为明确:
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")
}
}
印刷品:
F1 is COMPLETED
The program waited patiently for this callback to finish.
F2 is COMPLETED
F is COMPLETED
P is COMPLETED
The program waited patiently for this callback to finish.
如果你放弃了第一个期货的价值,那么进行两个期货是没有意义的。最好在一个单独的将来运行所有东西。这是为了尽可能地接近给定的代码。在一个实际的应用程序中,第一个未来将产生一个您实际使用的值。如果
map
和flatMap
完成了与onSuccess
相同的事情(以及更多,因为它们可以返回值),那么为什么onSuccess
会出现在API中呢?它是否仅用于对称性故障?或者是onSuccess
和onFailure
较低级别的构造,在它们的基础上map
和flatMap
被实现在引擎盖下?检查源代码似乎确实如此。我认为promises是一个低级别的API,如果可以避免的话,就不应该使用它。因此,第一个例子使用AND,第二个更好。确切地说。Promise是的功能,然后在引擎盖下使用onComplete
处理程序执行同步。在Promise
的示例中,如果您在打印此程序之前睡觉…
它将永远不会打印。我认为这个例子的问题与原来的问题相同——没有什么东西在等待p.future.onSuccess
。在第一个例子中,如果你在做wait.ready(f2,Duration.Inf)
并且f2
是f1
的延续,那么为什么需要wait.ready(f1,Duration.Inf)
?@DannyVarod如果你只想等待一切完成,你不需要两种等待。然而,如果您想分别看到每个期货的完成,特别是f2比f1需要更长的时间,两种等待都是有用的。