第一个 for-callback 几乎每次都打印未来列表,第二个 onComplete-callback 很少 returns 成功(从不失败)

First for-callback prints future list almost every time, second onComplete-callback rarely returns success (never failure)

我正在查看一些 Future 示例。我有一个 Future,它从一个方法中检索一个列表。我调用了两种不同类型的回调,一个 Foreach 回调和一个 onComplete 回调,只是为了尝试一下。

有人可以向我解释一下发生了什么吗?

我了解回调确实并发执行,并且没有顺序。但是如果 Future 正在 return 将列表发送到 Foreach 并且 onComplete 回调在 Foreach 和 Future 之前执行并且它试图从不成功的 Future 中获取列表,那么 onComplete 回调 return 不应该失败吗?

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}

object FuturesExampleObj extends App {

  println("Using Future to retrieve list\n")
  val l: Future[List[String]] = Future {
    getList()
  }

  println("FOR CALLBACK --------------------\n")

  l foreach {
    items =>
      for(item <- items) println(s"foreach item : $item")
      println("\n")
  }

  println("onComplete CALLBACK --------------------\n")

  l onComplete {
    case Success(i) => println(s"SUCCESS : $i")
    case Failure(i) => println(s"FAILURE : $i")
  }

  def getList(): List[String] ={
    val list = ("a" :: "b" :: "c" :: "d" :: "e":: Nil)
    list
  }
}

结果示例 1(常见)

Using Future to retrieve list

FOR CALLBACK --------------------

onComplete CALLBACK --------------------

foreach item : a
foreach item : b
foreach item : c
foreach item : d
foreach item : e



Process finished with exit code 0

结果示例 2(不常见)

Using Future to retrieve list

FOR CALLBACK --------------------

onComplete CALLBACK --------------------


Process finished with exit code 0

结果示例 3(非常罕见)

基本上 onComplete 永远不会 return 成功或失败。有时,在极少数情况下,它会 return "SUCCESS: " + 列出。

原因是应用程序的线程在 Future 完成之前完成。

只需在程序的和处添加 Await.ready(l, Duration.Inf).value.get

这样做只是为了测试!

这是因为你必须明确阻止未来。 在您的情况下,主线程在 onComplete 完成之前终止,有时在 l foreach .. 完成之前终止。

请补充:

import scala.concurrent.{Await, Future}
import scala.concurrent.duration._

val listF = l foreach {
  items =>
    for(item <- items) println(s"foreach item : $item")
    println("\n")
}

Await.result(listF, 5 seconds)

这样你就可以等待这个未来的完成。

如果要等待onComplete,则需要使用Thread.sleep(在onComplete之后添加,例如:

l onComplete {
   case Success(i) => println(s"SUCCESS : $i")
   case Failure(i) => println(s"FAILURE : $i")
}

Thread.sleep(3000)

onComplete 在 ExecutionContext 中的某个线程上运行,而 Await 在当前线程上运行,并阻塞它直到它完成或超过指定的超时。 因此 onComplete 是非阻塞的,而 Await 是阻塞的。

使用 onComplete 我们不会阻塞 Future 的结果,相反,我们将收到 SuccessFailure 的回调。

Thread.sleep() 正在阻塞我们的主线程,以便我们可以看到未来的异步结果。

请注意,您不应在生产代码中使用 Await.result,它用于测试 Future 的输出。 此外,您肯定不会使用 Thread.sleep(),而是使用 "react" 作为 future 返回的结果。

通常,您会有一些 REST API 调用或其他正在运行并等待未来完成的服务。