我正在看一些未来的例子。我有一个Future从方法中检索列表。我调用两种不同的回调,一个Foreach回调和一个onComplete回调只是为了尝试它们。
有人可以向我解释发生了什么吗?
我知道回调确实是并发执行的,并且没有命令。但是,如果Future将列表返回给Foreach并且在Foreach和Future之前执行了onComplete回调,并且它试图从失败的Future中获取列表,那么onComplete回调不应该返回FAILURE吗?
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永远不会返回SUCCESS或FAILURE。有时,很少会返回“ SUCCESS:” +列表。
答案 0 :(得分:2)
这是因为您必须明确阻止未来。
对于您来说,主线程在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
的结果,而是会收到Success
或Failure
的回调。
Thread.sleep()
正在阻塞我们的主线程,以便我们可以看到将来的异步结果。
请注意,您不应在生产代码中使用Await.result
,它用于测试Future的输出。
此外,您肯定不会使用Thread.sleep()
,而是会对将来返回的结果“做出反应”。
通常,您将有一些REST API调用或另一项服务正在运行,并等待将来完成。
答案 1 :(得分:1)
原因是应用程序的线程在Future
完成之前完成。
只需在程序的和处添加Await.ready(l, Duration.Inf).value.get
。
仅用于测试!