我们有一个Scala,它作为HTTP请求的一部分执行许多数据库操作,每个请求都是一个未来。通常,我们会将“期货”泡到一个异步控制器动作,然后让处理等待它们。
但我也注意到,在许多地方,我们没有幻想未来,甚至没有等待它完成。我认为这很糟糕,因为这意味着如果将来失败,HTTP请求不会失败,但是它实际上是否保证将来会被执行,因为没有什么会等待它的结果?在HTTP请求被送达后,会玩掉期待已久的期货吗?还是让它们在后台运行?
发布于 2017-01-26 10:13:50
TL;博士
Future。Future失败,将不会报告错误。长版本
在发送HTTP响应时,您的未来不会被扼杀。你可以像这样为自己尝试一下:
def futuresTest = Action.async { request =>
println(s"Entered futuresTest at ${LocalDateTime.now}")
val ignoredFuture = Future{
var i = 0
while (i < 10) {
Thread.sleep(1000)
println(LocalDateTime.now)
i += 1
}
}
println(s"Leaving futuresTest at ${LocalDateTime.now}")
Future.successful(Ok)
}然而,你是对的,如果任何未来失败,请求不会失败。如果这是一个问题,那么您可以使用进行理解,或flatMaps组合期货。下面是一个例子,说明你可以做些什么(我假设你的期货只会产生副作用(Future[Unit]) )
让你的未来在平行线上执行
val dbFut1 = dbCall1(...)
val dbFut2 = dbCall2(...)
val wsFut1 = wsCall1(...)
val fut = for(
_ <- dbFut1;
_ <- dbFut2;
_ <- wsFut1
) yield ()
fut.map(_ => Ok)让他们按顺序执行
val fut = for(
_ <- dbCall1(...);
_ <- dbCall2(...);
_ <- wsCall2(...)
) yield ()
fut.map(_ => Ok)发布于 2017-01-27 08:01:03
它是否真的保证将来会被执行,因为没有什么会等待它的结果?在HTTP请求被送达后,会玩掉期待已久的期货吗?还是让它们在后台运行?
这个问题实际上比玩得深得多。您通常会问:“如果我不同步地等待未来,我如何保证它能够在没有GCed的情况下真正完成呢?”要回答这个问题,我们需要了解GC实际上是如何查看线程的。从GC的角度来看,线程就是我们所说的“根”。这样的根是堆遍历其对象并查看哪些对象符合收集条件的起点。根中也有静态字段,例如,已知在应用程序的整个生命周期中都存在这些字段。
因此,当您这样查看它时,想想Future实际做了什么,它是在通过底层ExecutorService (我们在Scala中称为ExecutionContext )可用的线程池上运行在专用线程上的函数队列,您可以看到,即使您没有等待完成,JVM运行时确实保证您的Future将运行到完成。至于包装函数的Future对象,它保存对未完成函数体的引用,因此不收集Future本身。
从这个角度来看,这是完全合乎逻辑的,因为Future的执行是异步的,我们通常继续使用map、flatMap、onComplete等的异步方式来处理它。
https://stackoverflow.com/questions/41869585
复制相似问题