我应该阻止未来 - 斯卡拉

时间:2016-12-29 14:27:45

标签: scala

根据Scala文档,不应该对Future进行阻止。

“正如前面所提到的,为了表现和防止僵局,强烈建议阻止未来。期货的回调和组合是使用其结果的首选方式。但是,在某些情况下可能需要阻止并得到Futures and Promises API的支持。“

在我的程序退出之前,如何确保我的所有期货已完成(以及他们的回调已完成)?我通常在主函数结束时使用Await.result来确保所有Futures都已完成。

object ConcurrencyExample extends App {
val gpf= Future {some operations}
val ccf = Future{some operations}


val atbf = for {g <- gpf
c <- ccf if c == true}  yield {some operations}

//is it OK to use Await? If not, how do I ensure that all Futures have finished
        ?
Await.result(atbf,1000 millis )
 }

问题

  1. 使用Await错了吗?我的代码不等待Futures以其他方式完成
  2. 如果是这样,有什么选择?
  3. 如何在主程序退出之前确保Future及其回调已完成?

1 个答案:

答案 0 :(得分:7)

是的,你可以Await.result

  

您可以使用Await.result保持主线程的活着,以便完成期货

对Await.result感到满意

请注意,这适用于Akka和播放应用

  只有在绝对必要时才应非常小心地使用

Await.result

Await.result阻止运行它的线程,直到给定的持续时间。阻塞线程将浪费宝贵的计算资源,因为该线程将无法执行任何有用的计算,如处理新请求或算法中的数字运算等。

因此,尽量避免使用Await.result

  

但是,我们什么时候使用它(Await.result)?

以下是使用Await.result的典型用例之一。

假设您已编写包含主线程的程序,并且主线程内的所有计算都是异步的。现在,一旦在主线程内启动异步计算。有些人必须停止主线程的存在,直到异步计算完成,如果不是程序停止运行,你就看不到异步计算的结果。

  

当应用程序开始运行时,有一个非守护程序线程,其作用是执行main()。除非非守护程序线程完成,否则JVM不会自行退出。

object Main {
 def main(args: Array[String]): Unit = {
  import scala.concurrent.Future
  import scala.concurrent.duration._

  val f = Future { //do something }
  //stop main thread till f completes
  Await.result(f, 10 seconds)
 }
}
  

Future使用守护程序线程进行运行。因此守护程序线程无法阻止JVM关闭。因此,即使非守护程序线程正在运行,JVM也会关闭。

在上面的例子中,没有其他方法可以阻止(阻塞)主线程直到计算f完成,如果主线程没有退出并且计算停止。

  

在大多数情况下,您不需要使用Await.result,使用Futuremap进行简单flatMap合成就足够了。

使用Await.result的风险(通常所有阻止代码)

  

在基于事件的模型中耗尽线程

在基于事件的模型中,如果您有阻塞代码需要很长时间才能返回,那么您将很快耗尽线程。在playframework中,任何阻塞调用都可能降低应用程序的性能,并且应用程序在线程耗尽时会变得很慢。

  

在基于非事件的模型中耗尽内存

在每个请求模型的线程中。当您有阻止呼叫时需要很长时间才能退出/返回。

案例1:如果你有固定的线程池,那么应用程序可能会用完线程。

案例2:如果你有一个动态增长的线程池,你的应用程序将遭受过多的上下文切换开销,并且由于内存中被阻塞的线程太多,内存也会耗尽。

在所有情况下,等待某些IO或其他事件都无法完成任何有用的工作。