根据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 )
}
问题
答案 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
,使用Future
和map
进行简单flatMap
合成就足够了。
使用Await.result的风险(通常所有阻止代码)
在基于事件的模型中耗尽线程
在基于事件的模型中,如果您有阻塞代码需要很长时间才能返回,那么您将很快耗尽线程。在playframework中,任何阻塞调用都可能降低应用程序的性能,并且应用程序在线程耗尽时会变得很慢。
在基于非事件的模型中耗尽内存
在每个请求模型的线程中。当您有阻止呼叫时需要很长时间才能退出/返回。
案例1:如果你有固定的线程池,那么应用程序可能会用完线程。
案例2:如果你有一个动态增长的线程池,你的应用程序将遭受过多的上下文切换开销,并且由于内存中被阻塞的线程太多,内存也会耗尽。
在所有情况下,等待某些IO或其他事件都无法完成任何有用的工作。