scala.concurrent.blocking 的不良用例?
bad use cases of scala.concurrent.blocking?
关于 this 接受的答案中的第三点,是否存在使用 blocking
进行长 - 运行 计算毫无意义或不好的情况,无论是 CPU- 还是 IO-bound,正在执行 'within' a Future
?
, blocking
+ ForkJoinPool
如果你有很多消息要处理并且每个消息都需要长时间阻塞(这也意味着它在此期间保留了一些记忆)。 ForkJoinPool
创建新线程来补偿 "managable blocked" 线程,而不考虑 MaxThreadCount
;向 VisualVm 中的数百个线程问好。而且它几乎消除了背压,因为池的队列中总是有任务的位置(如果你的背压基于 ThreadPoolExecutor
的策略)。性能被新线程分配和垃圾收集所扼杀。
所以:
- 当消息速率不高于 1/blocking_time 时很好,因为它允许您使用线程的全部功能。一些智能背压可能有助于减慢传入消息的速度。
- 如果某个任务在
blocking{}
期间实际使用了您的 CPU(无锁),那是没有意义的,因为它只会增加线程数,而不是系统中的实际内核数。
- 并且对于任何其他情况都不利 - 那么您应该使用单独的固定线程池(并且可能轮询)。
P.S。 blocking
隐藏在 Await.result
中,所以并不总是很明显。在我们的项目中,有人只是在一些底层 worker actor 中做了这样的 Await
。
这取决于 ExecutionContext
你的 Future
被执行。
毫无意义:
如果 ExecutionContext
不是 BlockContext
,那么使用 blocking
将毫无意义。也就是说,它将使用 DefaultBlockContext,它只执行代码而无需任何特殊处理。它可能不会增加那么多开销,但仍然毫无意义。
差:
Scala 的 ExecutionContext.Implicits.global
会在线程池即将耗尽时在 ForkJoinPool
中生成新线程。也就是说,如果它 知道 那将通过 blocking
发生。如果您正在生成 lots 个线程,这可能会很糟糕。如果您在短时间内排队处理大量工作,global
上下文将愉快地扩展直到陷入僵局。 @dk14 的回答对此进行了更深入的解释,但要点是它可能成为性能杀手,因为托管阻塞实际上很快就会变得难以管理。
blocking
的主要目的是避免线程池内的死锁,因此它与性能无关,因为达到死锁比产生更多线程更糟糕。但是,它绝对不是神奇的性能提升器。
我写了更多关于 blocking
的文章,特别是在 。
关于 this 接受的答案中的第三点,是否存在使用 blocking
进行长 - 运行 计算毫无意义或不好的情况,无论是 CPU- 还是 IO-bound,正在执行 'within' a Future
?
blocking
+ ForkJoinPool
如果你有很多消息要处理并且每个消息都需要长时间阻塞(这也意味着它在此期间保留了一些记忆)。 ForkJoinPool
创建新线程来补偿 "managable blocked" 线程,而不考虑 MaxThreadCount
;向 VisualVm 中的数百个线程问好。而且它几乎消除了背压,因为池的队列中总是有任务的位置(如果你的背压基于 ThreadPoolExecutor
的策略)。性能被新线程分配和垃圾收集所扼杀。
所以:
- 当消息速率不高于 1/blocking_time 时很好,因为它允许您使用线程的全部功能。一些智能背压可能有助于减慢传入消息的速度。
- 如果某个任务在
blocking{}
期间实际使用了您的 CPU(无锁),那是没有意义的,因为它只会增加线程数,而不是系统中的实际内核数。 - 并且对于任何其他情况都不利 - 那么您应该使用单独的固定线程池(并且可能轮询)。
P.S。 blocking
隐藏在 Await.result
中,所以并不总是很明显。在我们的项目中,有人只是在一些底层 worker actor 中做了这样的 Await
。
这取决于 ExecutionContext
你的 Future
被执行。
毫无意义:
如果 ExecutionContext
不是 BlockContext
,那么使用 blocking
将毫无意义。也就是说,它将使用 DefaultBlockContext,它只执行代码而无需任何特殊处理。它可能不会增加那么多开销,但仍然毫无意义。
差:
Scala 的 ExecutionContext.Implicits.global
会在线程池即将耗尽时在 ForkJoinPool
中生成新线程。也就是说,如果它 知道 那将通过 blocking
发生。如果您正在生成 lots 个线程,这可能会很糟糕。如果您在短时间内排队处理大量工作,global
上下文将愉快地扩展直到陷入僵局。 @dk14 的回答对此进行了更深入的解释,但要点是它可能成为性能杀手,因为托管阻塞实际上很快就会变得难以管理。
blocking
的主要目的是避免线程池内的死锁,因此它与性能无关,因为达到死锁比产生更多线程更糟糕。但是,它绝对不是神奇的性能提升器。
我写了更多关于 blocking
的文章,特别是在