参考这个被接受的答案中提到的第三点,是否存在使用blocking
对于正在'within' Future
中执行的长时间计算(无论是CPU-bound还是IO-bound)毫无意义或不好的情况?
参考这个被接受的答案中提到的第三点,是否存在使用blocking
对于正在'within' Future
中执行的长时间计算(无论是CPU-bound还是IO-bound)毫无意义或不好的情况?
从我的实践来看, blocking
+ ForkJoinPool
可能会导致连续且不可控的线程创建,如果您有很多需要处理的消息,并且每个消息都需要长时间阻塞(这也意味着在此期间它占用一些内存)。ForkJoinPool
会创建新线程以补偿“可管理的阻塞”线程,而不考虑 MaxThreadCount
;在 VisualVm 中可能会出现数百个线程。它几乎杀死了反压力,因为池队列中始终有任务的位置(如果您的反压力基于 ThreadPoolExecutor
的策略)。性能会受到新线程分配和垃圾回收的影响。
所以:
blocking{}
(无锁)期间实际上使用了您的 CPU,那么它只会增加线程数而不是系统中真实核心的数量,这是毫无意义的。P.S. blocking
被隐藏在 Await.result
中,因此并不总是明显的。在我们的项目中,有人在某些底层工作 actor 中执行了这样的 Await
。
Future
的ExecutionContext
。如果ExecutionContext
不是BlockContext
,那么使用blocking
就没有意义。也就是说,它将使用DefaultBlockContext,该上下文仅执行代码而没有任何特殊处理。虽然它可能不会增加太多开销,但还是没有意义的。Scala的ExecutionContext.Implicits.global
是为了在线程池即将耗尽时在ForkJoinPool
中生成新线程。也就是说,如果它通过blocking
知道即将发生这种情况。如果你正在生成大量线程,这可能是不好的。如果你在短时间内排队了很多工作,global
上下文将愉快地扩展直到死锁。@dk14的答案更详细地解释了这一点,但要点是,它可能会成为性能杀手,因为管理阻塞实际上可能很快变得难以管理。 blocking
的主要目的是避免线程池中的死锁,因此它与性能有间接关系,因为达到死锁比生成更多线程更糟糕。但是,它绝对不是神奇的性能增强器。我在这个答案中更详细地介绍了blocking
。
ForkJoinPool
之外还有哪些支持阻塞的实现吗?我没有找到... - dk14