【问题标题】:The Difference between Parallel and Sequential Stream in terms of Java 1.8Java 1.8 中并行流和顺序流的区别
【发布时间】:2017-12-24 13:53:43
【问题描述】:

就 Java 1.8 而言,顺序流和并行流之间的功能区别是什么,输出将如何受到影响?

以及在哪些场景中选择并行或顺序流?

Java中顺序流和并行流的处理方法有什么区别?!!

我已经尝试在sn-p下面用少量数据测试它,我没有得到任何异常的输出差异。!!

ArrayList<Integer> arrayList = new ArrayList<>();
for(int i = 1; i <= 100;i++) arrayList.add(i);

arrayList.stream().filter(l -> l > 90).forEach(l -> System.out.println(l));

arrayList.parallelStream().filter(l -> l > 90).forEach(l -> System.out.println(l));

【问题讨论】:

  • parallelStream 可帮助您将处理分配到多个内核。您需要检查系统上的并行度:System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20")。更多信息请参考link

标签: java lambda java-8 functional-programming java-stream


【解决方案1】:

对于您的具体示例,您很幸运没有看到任何差异(将循环添加到 101 以便元素在线程之间分布得更差一点并看到差异)forEach 是记录为:

这个操作的行为是明确的非确定性的

因此,至少对于并行处理而言,不会有顺序 - 至少在某种意义上是您可以依赖的。有forEachOrdered确实保证订单 - 以备不时之需。

选择parallelsequential 并不容易 - 你应该衡量,Brian's advices are the best to read here

【讨论】:

    【解决方案2】:

    由于您正在创建并行流,因此流的元素可能由不同的线程处理。并行流允许多个线程独立地处理流的各个部分。您使用 parallelStream() 的代码说明了如何利用多个内核。

    当您在 100 个元素上使用 parallelStream() 时,您看不到很大的不同。你需要拥有更多。

    说到排序,还有两种方法可以实现,使用forEachforEachOrdered。它们之间的区别在于 forEach 将允许以任何顺序处理并行流的任何元素,而 forEachOrdered 将始终按照它们在原始流中出现的顺序处理并行流的元素。因此,在这种情况下,如果您按原样保留 forEach,则无法保证顺序。

    【讨论】:

    • @Eugene 刚刚用一些订购细节更新了我的答案。谢谢!
    【解决方案3】:

    通常,并行流基本上是将其元素划分为多个块的流,用不同的线程处理每个块。因此,您可以在多核处理器的所有内核上自动划分给定操作的工作负载,并使所有内核保持同样繁忙。

    但是,需要注意的是,仅调用 parallelStream() 并不一定会使流并行,事实上,调用此方法甚至可能返回顺序流而不是并行流。

    如 java 文档中所述:

    default Stream&lt;E&gt; parallelStream()

    返回一个可能并行的流,该集合作为其源。 此方法允许返回顺序流

    因此,我们可以得出结论,由库决定是否适合使用多线程。 在大多数情况下,当需要处理大量数据时会出现这种情况

    在您的情况下,ArrayList 中似乎只有 100 个元素,因此您是否使用 parallelStream() 没有区别。

    最后,但并非最不重要的一点是,我总是使用 顺序流 以顺序方式处理数据,除非需要处理大量数据或遇到性能问题使用顺序流处理数据问题,在这种情况下您可以切换到 parallelStream

    【讨论】:

    • 我猜 possibly 部分是例如 List.of(T t)Collections.singletonList 他们显然不能从并行处理中受益......
    • @Eugene 关于您的第一条评论,我的回答仍然有效。至于你的第二条评论,我想看看一些统计数据。
    • 没错,没有统计数据就不可能说哪个更快,但是 100 个元素的答案是显而易见的
    • @Eugene 我的答案是基于 OPs 当前示例,即 100 个元素,并且无论如何使用此类元素计数,无论您使用并行流还是顺序,性能差异都不算什么。但是,我想开导一下,看看有 101 个元素会导致性能差异;)
    • 我的意思不是性能问题,我的意思是线程之间的更好分布更少(通常是 2 的幂),因此在并行的情况下处理,无序输出的“更快”可见结果
    【解决方案4】:

    Stream 的文档声明 parallel 是流的属性,但没有添加太多关于实现规范的内容。

    不同之处在于对流的声明性操作的执行。在大多数情况下,除非就结果而言很重要,否则差异不会显示出来。

    可能在您调用的forEach 终端流方法中找到对差异的最佳解释。 Stream.forEach 的文档规定:

    此操作的行为明显是不确定的。 对于并行流管道,此操作不保证 尊重流的相遇顺序,因为这样做会牺牲 并行性的好处。对于任何给定的元素,动作可能是 在图书馆的任何时间和任何线程中执行 选择。如果动作访问共享状态,它负责 提供所需的同步。

    换句话说,顺序流以牺牲并发性为代价来保证顺序。仅此而已。

    【讨论】:

      【解决方案5】:

      顺序和并行的功能区别是什么 在 Java 方面流

      不应该有什么误解:并行处理和并发处理不是一回事。

      以及在哪些场景中选择并行或顺序流?

      使用并行流可能有益也可能无益,这实际上取决于您的用途。有时它们更快,有时甚至更慢。

      有句话说,如果你能做某事并不意味着你应该做。

      【讨论】:

        猜你喜欢
        • 2015-10-24
        • 2020-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多