当前位置: 首页 > 知识库问答 >
问题:

我是否应该在可能的情况下始终使用并行流?

史良哲
2023-03-14

使用Java 8和lambdas可以很容易地将集合作为流进行迭代,使用并行流也同样容易。文档中的两个示例,第二个使用ParallelStream:

myShapesCollection.stream()
    .filter(e -> e.getColor() == Color.RED)
    .forEach(e -> System.out.println(e.getName()));

myShapesCollection.parallelStream() // <-- This one uses parallel
    .filter(e -> e.getColor() == Color.RED)
    .forEach(e -> System.out.println(e.getName()));

只要我不关心顺序,使用平行会一直是有益的吗?人们会认为在更多的核心上分配工作是更快的。

还有其他考虑吗?什么时候应该使用并行流,什么时候应该使用非并行流?

(问这个问题是为了引发关于如何以及何时使用并行流的讨论,而不是因为我认为始终使用它们是一个好主意。)

共有2个答案

经炜
2023-03-14

Stream API的设计是为了使编写计算变得容易,而这种方法与它们的执行方式无关,从而使顺序和并行之间的切换变得容易。

但是,仅仅因为它很容易,并不意味着它总是一个好主意,事实上,仅仅因为可以,就把.parallel()放得满满当当是一个坏主意。

首先,请注意,当有更多的核心可用时,并行除了可以更快地执行之外,没有其他好处。并行执行总是比顺序执行涉及更多的工作,因为除了解决问题外,它还必须执行子任务的调度和协调。希望您能够通过将工作分解到多个处理器中来更快地得到答案;这是否真的发生取决于很多事情,包括数据集的大小、对每个元素进行的计算量、计算的性质(具体而言,一个元素的处理是否与其他元素的处理交互?)、可用处理器的数量以及竞争这些处理器的其他任务的数量。

此外,请注意,并行性还经常暴露计算中的不确定性,而这种不确定性通常被顺序实现所隐藏;有时这无关紧要,或者可以通过约束所涉及的操作来减轻(即,约简运算符必须是无状态和关联的。)

在现实中,有时并行会加快你的计算速度,有时不会,有时甚至会减慢计算速度。最好首先使用顺序执行进行开发,然后在其中应用并行性

(A)您知道提高性能实际上是有好处的

(B)它将实际提高业绩。

(A)是业务问题,而不是技术问题。如果您是性能专家,您通常能够查看代码并确定(B),但聪明的方法是度量。(而且,在你确信(A)之前,不要费心;如果代码足够快,最好把你的大脑循环应用到其他地方。)

最简单的并行性能模型是“NQ”模型,其中N是元素的数量,Q是每个元素的计算量。通常,在开始获得性能优势之前,您需要产品NQ超过某个阈值。对于像“从1n的数字相加”这样的低Q问题,您通常会看到n=1000n=10000之间的盈亏平衡。对于较高Q值的问题,您将在较低的阈值下看到断裂。

但现实却相当复杂。因此,在您达到experthood之前,首先要确定顺序处理在什么时候确实会使您付出代价,然后衡量并行性是否会有所帮助。

韦俊英
2023-03-14

与顺序流相比,并行流具有更高的开销。协调线程需要大量的时间。默认情况下,我将使用顺序流,只有在以下情况下才考虑并行流

>

  • 我有大量的项目要处理(或者每个项目的处理都需要时间并且是可并行的)

    我首先有一个性能问题

    我还没有在多线程环境中运行该进程(例如:在web容器中,如果我已经有许多请求要并行处理,那么在每个请求中添加一个额外的并行层可能会产生更多的负面影响,而不是正面影响)

    在您的示例中,性能无论如何都将由对system.out.println()的同步访问驱动,使此过程并行将不会产生任何影响,甚至是负面影响。

    此外,请记住,并行流不会神奇地解决所有同步问题。如果进程中使用的谓词和函数使用了共享资源,则必须确保所有内容都是线程安全的。特别是,如果你走平行路线,副作用是你真正要担心的事情。

    无论如何,衡量一下,不要猜!只有一个度量会告诉你并行性是否值得。

  •  类似资料:
    • 问题内容: 使用Java 8和lambda,可以很容易地将集合作为流进行迭代,也很容易使用并行流。docs中的两个示例,第二个示例使用parallelStream: 只要我不关心顺序,使用并行会始终有益吗?有人会认为,更快地将工作划分到更多的内核上。 还有其他考虑事项吗?什么时候应该使用并行流,什么时候应该使用非并行? (问这个问题可以引发关于如何以及何时使用并行流的讨论,不是因为我认为始终使用并

    • 我想使用并使其直接进入给定的url,而不是从ribbon配置中获取主机。 我知道在Spring,cloud-feign默认与ribbon和eureka一起出现。 根据这个:https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html#spring-cloud-ribbon-without-eure

    • 我将guava jar文件添加到类路径中,但我的IDE(eclipse)说: Nullable无法解析为类型 但如果我ctrl+单击Nullable,我会看到蓝色下划线,然后看到下划线:

    • 问题内容: 如果要使用Linq-SQL,还必须将DB Table拖到设计器表面以创建实体类。 我一直喜欢我的应用程序中的完全控制权,并且不喜欢dotnet创建的类。 是否可以使用我自己的数据访问层实体类在Linq和DB之间提供此连接? 我该如何完成? 问题答案: 您可以使用Linq-to-SQL非常轻松地编写自己的类-只需使用一些属性绘制类即可。 例如,这是我的一个项目中有一个非常简单的表,它可以

    • 是否可以在没有实体的情况下使用JpaRepository?在这种情况下,将其替换为DTO。 如下示例所示 这种情况有替代方案吗? 注意:DTO已经映射,但我不想创建视图来将此DTO转换为实体。 我已经验证了这个主题,但没有重大进展,请使用无实体的JpaRepository交互样式 我在试这个 接口- 公共接口BffDTOInterface2{ } 我有这个错误

    • 问题内容: 我正在评估JOOQ是否可在仍在开发中的新系统中使用。我想避免在与应用程序一起开发数据库时生成代码,而只是为该应用程序起持久存储的作用。因此,预计数据库模式定义将由Java代码(java中的表定义)驱动。 JOOQ是否适合上述用例?是否有用于模式定义的Java DSL? 问题答案: JOOQ是否适合上述用例? 是的,许多jOOQ用户仅使用运行时库,而没有代码生成器。入门指南中提供了示例。