我如何等待Scala future的onSuccess回调完成?

Dan*_* Li 14 concurrency scala future

在Scala中,我可以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)
    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)
  }
}
Run Code Online (Sandbox Code Playgroud)

我希望输出为:

The program waited patiently for this callback to finish.
Run Code Online (Sandbox Code Playgroud)

相反,没有输出; 程序在回调结束前退出.

请注意,这与等待未来完成的问题不同,这已在此问题中得到解答.

Rüd*_*ehn 20

不要使用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)
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您只想在成功的情况下执行副作用(例如在您的示例中),则映射是合适的.如果你想在失败的情况下执行副作用,那么这是正确的使用方法.在scala-user上查看Roland Kuhn的这篇文章.

另外,请不要在生产代码附近的任何地方使用Thread.sleep.


yǝs*_*ǝla 8

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")
  }
}
Run Code Online (Sandbox Code Playgroud)

打印:

F1 is COMPLETED
The program waited patiently for this callback to finish.
F2 is COMPLETED
Run Code Online (Sandbox Code Playgroud)

使用承诺更加清晰:

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")
  }
}
Run Code Online (Sandbox Code Playgroud)

打印:

F is COMPLETED
P is COMPLETED
The program waited patiently for this callback to finish.
Run Code Online (Sandbox Code Playgroud)