我如何等待Scala的未来';s onSuccess回调是否要完成?

我如何等待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

在Scala中,我可以使用
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需要更长的时间,两种等待都是有用的。