Java 8:首先使用stream()或parallelStream()非常慢 - 在实践中使用有意义吗?

Vei*_*ver 6 java java-8 java-stream

在过去的几天里,我使用Java 8中的外部迭代,流和parallelStream进行了一些测试,并测量了执行时间的持续时间.我还读到了我必须考虑的热身时间.但仍有一个问题.

第一次调用方法stream()parallelStream()集合时,执行时间高于外部迭代.我已经知道,当我在同一个集合上调用stream()parallelStream()更频繁地调用执行时间时,那么parallelStream()确实比外部迭代更快.但由于实际上集合通常只迭代一次,我只看到使用流或并行流的缺点.

所以我的问题是:

如果我只迭代一次集合,那么使用流或者parallelStream()或者执行时间是否总是高于外部迭代?

Stu*_*rks 7

完全巧合(显然),Doug Lea,Brian Goetz和其他几个人写了一篇名为Stream Parallel Guidance的文件.(这只是一个草案.)它确实有一些关于何时使用并行和顺序流的有用讨论.

简要总结:并行流的启动成本比顺序流更昂贵.如果您的工作负载是可拆分的,并且您有多个可以解决问题的CPU核心,并且每个元素的成本不是非常小,那么您将获得具有足够大工作负载的并行加速.(对于很多条件问题,这是怎么回事?)哦,你还需要注意基准测试.

StackOverflow充斥着试图并行添加几个整数然后声称并行流不好的问题,因为它们不提供任何加速.我甚至不打扰与他们联系.

现在,您已经询问过"外部迭代"(基本上是for-loop)vs流,并行或顺序.我认为重要的是考虑并行和顺序流,正如我上面所做的那样.这将有助于做出进一步的决定.显然,如果有可能你需要并行运行,那么你应该选择流,即使你最初是顺序启动的.

即使您不打算并行,for循环和顺序流之间仍有许多考虑因素.与传统循环相比,存在一定量的流开销 - 尤其是阵列上的循环.但这通常是在工作量上摊销的.即使集合仅迭代一次,如果集合中的元素数量足够大,也可以进行设置的摊销.例如,如果集合有10个元素,则流的额外设置成本可能不值得.如果集合有10,000个元素,那么它可能是另一个故事.

数组上的for循环特别快,因为唯一的"设置"是初始化循环计数器并限制寄存器中的值.JIT编译器也可以带来许多循环优化.顺序流很少能在阵列上击败for循环,尽管它可能会发生.

集合上的for循环通常涉及创建迭代器,因此比基于数组的循环有更多的开销.特别是,迭代器上的每次迭代都涉及对方法的调用hasNext,next而流可以通过单个方法调用获取每个元素.由于这个原因,有时候顺序流可以击败基于迭代器的循环(给定正确的每元素工作负载,足够多的元素等).因此,即使流有一些设置成本,也有可能最终运行速度比传统的for循环更快.

最后,表现不是唯一的考虑因素.还具有可读性和可维护性.流和lambda的东西最初可能是新的和不熟悉的,但它具有简化和清理代码的巨大潜力.例如,请参阅对其他问题的回答.