当前位置: 首页 > 面试题库 >

来自HashSet的并行流不会并行运行

龙志勇
2023-03-14
问题内容

我有要并行处理的元素的集合。当我使用时List,并行性有效。但是,当我使用时Set,它不会并行运行。

我写了一个代码样本来说明问题:

public static void main(String[] args) {
    ParallelTest test = new ParallelTest();

    List<Integer> list = Arrays.asList(1,2);
    Set<Integer> set = new HashSet<>(list);

    ForkJoinPool forkJoinPool = new ForkJoinPool(4);

    System.out.println("set print");
    try {
        forkJoinPool.submit(() ->
            set.parallelStream().forEach(test::print)
        ).get();
    } catch (Exception e) {
        return;
    }

    System.out.println("\n\nlist print");
    try {
        forkJoinPool.submit(() ->
            list.parallelStream().forEach(test::print)
        ).get();
    } catch (Exception e) {
        return;
    }   
}

private void print(int i){
    System.out.println("start: " + i);
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
    }
    System.out.println("end: " + i);
}

这是我在Windows 7上获得的输出

set print
start: 1
end: 1
start: 2
end: 2

list print
start: 2
start: 1
end: 1
end: 2

我们可以看到中的第一个元素Set必须在处理第二个元素之前完成。对于List,第二个元素在第一个元素结束之前开始。

您能否告诉我是什么原因导致此问题,以及如何使用Set集合避免发生此问题?


问题答案:

我可以重现您看到的行为,其中并行性与您指定的fork-join池并行性的并行性不匹配。将fork-
join池的并行度设置为10,并将集合中的元素数增加到50后,我看到基于列表的流的并行度仅上升到6,而基于集合的流的并行度从未超过2。

但是请注意,这种将任务提交给fork-join池以在该池中运行并行流的技术是一种“技巧”,并且 不能保证 能正常工作。实际上, 未指定
用于执行并行流的线程或线程池。默认情况下,使用公共的fork-join池,但是在不同的环境中,最终可能会使用不同的线程池。(请考虑应用程序服务器内的容器。)

在java.util.stream.AbstractTask类中,该LEAF_TARGET字段确定完成的拆分数量,而拆分又确定了可以实现的并行数量。该字段的值基于ForkJoinPool.getCommonPoolParallelism()哪个当然使用了公共池的并行性,而不取决于运行任务的任何池。

可以说这是一个错误(请参阅OpenJDK问题JDK-8190974),但是,整个区域都未指定。但是,系统的这一领域肯定需要发展,例如在拆分策略,可用并行性,处理阻塞任务等方面。JDK的未来版本可能会解决其中一些问题。

同时,可以通过使用系统属性来控制公共fork-join池的并行性。如果将此行添加到程序中,

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "10");

并且您在公共池中运行流(或者,如果将它们提交到具有足够高的并行性集的自己的池中),您会发现有更多的任务并行运行。

您也可以使用-D选项在命令行上设置此属性。

同样,这不是保证的行为,将来可能会改变。但是在可预见的将来,该技术可能会对JDK 8实现有效。

更新2019-06-12:
JDK-8190974
错误已在JDK
10中修复,并且该修复已向后移植到即将发布的JDK 8u版本(8u222)中。



 类似资料:
  • 我有要并行处理的元素集合。当我使用时,并行性起作用。但是,当我使用时,它不会并行运行。

  • 我有超过50种不同类型的输入,我在功能文件中的Example关键字下定义了这些输入,执行这些输入需要花费更多的时间。有没有办法并行运行这些输入?。我不想让任何人来测试这种方法。请帮忙。

  • 问题内容: 我同时运行两个AJAX请求时遇到问题。我有一个PHP脚本正在将数据导出到XSLX。此操作需要很多时间,因此我尝试向用户显示进度。我正在使用AJAX和数据库方法。实际上,我非常确定它曾经可以工作,但是我不知道为什么,它不再在任何浏览器中都能工作。新浏览器有什么变化吗? 在数据库中正确更新进度 JS计时器正在尝试获取进度,我可以在控制台中看到它,但是所有这些请求都加载第一个脚本的整个持续时

  • 我正在尝试动态生成阶段以并行运行,但面临下一个错误: WorkflowScript:59:第59行第5列的阶段“主”应为“步骤”、“阶段”或“平行”之一。阶段('main'){^ 这是詹金斯管道: 有办法解决这个问题吗? 谢谢

  • 在里面https://ci.apache.org/projects/flink/flink-docs-release-1.8/concepts/programming-model.html#parallel-数据流,有一个描述 操作符子任务的数量是该特定操作符的并行度。流的并行性始终是其生成操作符的并行性。同一程序的不同操作符可能具有不同的并行级别。 我不明白什么是流的并行性总是它的生成操作符的并