【问题标题】:Why in this snippet parallel execution is taking longer than sequential? [duplicate]为什么在这个片段中并行执行比顺序执行花费更长的时间? [复制]
【发布时间】:2020-03-31 12:55:22
【问题描述】:

以下代码的并行执行比顺序代码花费的时间更长。我知道并行流比顺序流更复杂,也更昂贵,我们不能指望并行流一直都能创造奇迹。我只关心下面的代码

List<Integer> collect = IntStream.rangeClosed(1, 1000000)
    .unordered()
    .parallel()
    .filter(e -> e%7 == 0)
    .boxed()
    .collect(Collectors.toList());

    long endTime = System.nanoTime();

    collect.forEach(System.out::println);
    System.out.println(endTime - startTime);

输出:

  • 使用顺序流:40 227 795

  • 使用并行流:74 656 768

这个流是有状态的吗? 如果不是,那么为什么并行流需要更长的时间? 这背后的原因是什么? 能有一个准确的猜测吗?

【问题讨论】:

标签: java parallel-processing java-stream


【解决方案1】:

默认情况下,Stream.parallel() 使用ForkJoinPool.commonPool() 作为其线程池。该池中的线程是动态分配的。这意味着,如果您单独运行上述代码,您的基准测试包括 ThreadFactory 生成线程所需的时间 (a somewhat expensive operation)。

在这种情况下,您更有可能获得以下好处:

  • 通过例如在启动计时器之前执行另一个并行流操作来预热线程池。
  • 增加线程工作负载的大小。您所做的工作相当琐碎,因此(显然)需要流中超过 100 万个项目才能显示收益。

请注意,ForkJoinPool.commonPool() 在其池中最多有 (#cores - 1) 个线程,因此在不同的计算机上运行相同的测试可能会得到更好或更差的结果 - 但请记住,对于较小的工作负载,更少 由于开销减少,线程更有可能显示出好处。

【讨论】:

    【解决方案2】:

    您正在并行处理某些东西的唯一事实并不总是意味着这将比顺序处理更快。这是编程中一个相当复杂的话题。 C#here中有一个关于这个问题的话题。但它也可以应用于 Java。

    简而言之,创建新线程是一项非常昂贵的操作,而且创建它确实需要时间。此外,在多线程环境中工作需要所谓的上下文切换,这与通常有比实际内核更多的进程有关,因此它们在执行某些操作时需要共享内核,这也是相当昂贵的。您可以找到一些与任何特定编程语言无关的温和介绍,而是关注一般问题here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-25
      相关资源
      最近更新 更多