2

在使用 phantom 时,在 db 调用中遵循这种模式有多危险:

Await.result(dbOperationFut, 30.seconds)

这并不是真正的幻象,但它是正在使用的 scala 驱动程序。

我厌倦了这种模式,因为潜在的 GC 暂停可能会持续超过 x 秒。考虑到 GC 暂停,多少秒是安全的?

我个人赞成使用 for-comp 而不是像这样阻塞,但只是想知道这是否是一种非常糟糕的做法还是很好。

上下文:这将用于基于 akka 的应用程序(akka,akka http)

想法?

4

1 回答 1

4

小心 Await.result

请注意,这适用于 Akka 和 play 应用程序

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组合,使用mapflatMap就足够了。

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

基于事件的模型中的线程用完

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

在非基于事件的模型中内存不足

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

情况 1:如果您有固定的线程池,则应用程序可能会用完线程。

情况 2:如果您有动态增长的线程池,那么您的应用程序将遭受过多的上下文切换开销,并且还会因为内存中的阻塞线程过多而耗尽内存。

在所有情况下,除了等待某些 IO 或其他事件之外,没有完成任何有用的工作。

于 2016-11-25T09:52:15.347 回答