scala.concurrent.blocking的坏用例?

时间:2015-04-16 00:42:01

标签: scala concurrency blocking

参考this接受的答案中的第三点,是否存在使用blocking进行长时间运行计算无论是CPU还是IO-毫无意义或不好的情况绑定,即在Future内执行?

2 个答案:

答案 0 :(得分:5)

From my practiceblocking + ForkJoinPool如果要处理大量消息并且每个消息需要长时间阻止(这也意味着它),可能导致线程的连续和无法控制的创建在此期间保留一些记忆。无论ForkJoinPool如何,MaxThreadCount都会创建新线程以补偿“可管理的被阻止”线程。向VisualVm中的数百个线程问好。它几乎会杀死背压,因为池中的任务总是有一个位置(如果你的背压基于ThreadPoolExecutor的策略)。新线程分配和垃圾收集都会破坏性能。

所以:

  • 当消息速率不高于1 / blocking_time时很好,因为它允许您使用完整的线程功能。一些智能背压可能有助于减慢传入的消息。
  • 如果一个任务在blocking{}(无锁)期间实际使用你的CPU是没有意义的,因为它只会增加线程数而不是系统中真实核心数。
  • 对于任何其他情况都不好 - 你应该使用单独的固定线程池(也许是轮询)。

P.S。 blocking隐藏在Await.result内,因此并不总是很明显。在我们的项目中,有人在一些基础工作者角色中做了这样的Await

答案 1 :(得分:4)

这取决于您ExecutionContext正在执行的Future

<强>毫无意义:

如果ExecutionContext不是BlockContext,那么使用blocking将毫无意义。也就是说,它将使用DefaultBlockContext,它只是执行代码而无需任何特殊处理。它可能不会增加那么多开销,但仍然毫无意义。

<强>为:

当线程池即将耗尽时,Scala的ExecutionContext.Implicits.global将在ForkJoinPool中生成新线程。也就是说,如果知道将通过blocking发生。如果您正在生成批次线程,这可能会很糟糕。如果您在很短的时间内排队等待大量工作,global上下文将很快扩展,直到陷入僵局。 @ dk14的答案更深入地解释了这一点,但要点是它可能是一个性能杀手,因为托管阻塞实际上很快就会变得无法管理。


blocking的主要目的是避免线程池中的死锁,因此它与性能在切向相关,因为达到死锁会比产生更多线程更糟糕。但是,它绝对不是一个神奇的性能增强器。

我已在this answer中详细了解了blocking