2017-01-26 35 views
2

我们有一个Scala Play网络应用程序,它将许多数据库操作作为HTTP请求的一部分,每个都是未来。通常我们会将期货泡沫化为异步控制器操作,并让Play处理等待它们。是否需要等待所有期货以保证其执行?

但我也注意到在一些地方我们不会冒泡未来或者等待它完成。我认为这是不好的,因为这意味着如果将来失败,HTTP请求不会失败,但它确实能保证未来将被执行,因为没有任何事情会等到它的结果?播放HTTP请求后播放是否会放弃未预期的期货,或者让它们在后台运行?

回答

2

TL;发送HTTP响应后DR

  1. 播放不会杀你Future秒。
  2. 如果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。下面是你可以做什么的例子(我假设你的期货只进行侧efects(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) 
1

它实际上连保证未来将在所有被执行,因为 没有什么要等待它的结果?会播放下降 HTTP请求送达后未期待的期货,还是让 在后台运行?

这个问题实际上比Play更深入。你通常会问:“如果我不同步等待未来,我怎么能保证它会在没有GCed的情况下实际完成?”。要回答这个问题,我们需要了解GC如何实际查看线程。从GC角度来看,线程就是我们所说的“根”。这样的根就是堆遍历它的对象并查看哪些可以收集的起点。例如,在根中也有静态字段,这些字段在应用程序的整个生命周期中都是已知的。

所以,当你看到它这样,并认为一个什么样的Future实际上做,这是队列从可用线程池通过底层ExecutorService一个专门的线程(我们称之为ExecutionContext运行的函数在Scala中),你会发现即使你没有等待完成,JVM运行时确实保证你的Future将运行完成。至于包装该函数的对象Future,它保存对该未完成函数体的引用,因此Future本身未被收集。

当你从这个角度看想想看,这是完全合乎逻辑的,因为Future的执行异步发生,而我们平时使用的延续,如mapflatMaponComplete

继续处理它以异步方式
相关问题