为什么 IntStream.range(0,n) in Java 8 不应该平行?

Why IntStream.range(0,n) in Java 8 shouldn't be parallel?

我读过一本关于 Java 8 的书,书中说使用并行流通过 IntStream.range(0,someNumber) 获取数字范围可能比顺序流慢...为什么那个?

它可以更慢。默认情况下,您应该始终使用顺序流。与顺序流相比,并行流的开销要高得多,因为它需要大量的内部协调工作以及某些簿记活动。

如果出现以下情况,您应该考虑并行的: 1.你有大量的项目要处理,每个项目都需要大量的时间并且可以并行化。 2. 如果您首先遇到性能问题。因此,在尝试并行流或任何其他并发构造之前,黄金法则始终是基准。

在您的情况下,如果范围非常小,那么在这种情况下,与并行流相关的开销会覆盖您应该获得的好处。另请查看这篇文章:http://zeroturnaround.com/rebellabs/java-parallel-streams-are-bad-for-your-health/

无论你从这本书中拿走什么都是错误的(或者充其量,是一种严重的过度简化。)因为你没有说是什么书,我们不知道是这本书错了还是你误解了。

能否获得并行加速取决于很多因素;源的可拆分性、流上的操作、行为参数所做的工作以及硬件。拥有不可拆分的源肯定会破坏并行性能;例如,LinkedList 不太可能很好地并行化。

This talk 更详细地介绍了使用并行性的哪些因素可能会加快计算速度、减慢计算速度或两者都不会,以及如何识别流管道的可能并行行为。

这本书(或您的解释)出错的地方是把责任归咎于IntStream.range;它是最好的分裂来源之一。因此,如果您的管道没有很好地并行化,那肯定是 而不是 因为您使用 IntStream.range 作为源,但也可能是出于其他原因(数据太少,终端操作合并成本高等)

世界上没有神奇的平行尘埃;流可以让您轻松编写并行代码,但并不能免除您了解并行成本模型的需要。但是,如果有人告诉您 IntStream.range 是问题所在,我建议您不要听他们的——这是非常危险的错误建议。

这在很大程度上取决于场景。处理器有开销来启动并行线程并处理它们。因此,如果您希望 运行 的过程不需要太多时间,那么这将浪费 CPU 个周期。

另一方面,我正在编写一个数据生成方法。为此,我使用了并行流,它至少提高了 4 倍的性能。在我的例子中,每个并行线程负责在数据库中进行多次读写,因此每个线程的处理时间相当长。

P.S.:可以设置属性:java.util.concurrent.ForkJoinPool.common.parallelism。如果您编写的进程依赖于并行线程的数量,这将很有用。默认情况下,.parallel() 将为每个核心启动一个线程。

在使用 parallelStream () 之前,请阅读:

  1. 它是多线程的。在 java 中,仅仅编写 parallelStream() 来获得并行性几乎总是坏主意。在某些情况下它会起作用,但并非总是如此。还有其他方法可以实现并行性,几乎总是,在采用多线程解决方案之前,您需要多加考虑。
  2. 它使用默认的 JVM 线程池。因此,如果您正在进行网络调用等任何阻塞操作,整个 java 应用程序可能会卡住。那是那里最大的问题。还有其他具有任务分配的。具有 n 个线程的简单 ExecutionService 提供比并行流更好的性能。

您还可以阅读: Java Parallel Streams Are Bad for Your Health! | JRebel by Perforce