java - 在考虑并行化外部流之前,是否会完全并行处理内部并行流?

标签 java concurrency java-8 java-stream forkjoinpool

从这里link ,我只是部分地理解,至少在某些时候,java 嵌套并行流存在问题。但是,我无法推断出以下问题的答案:

假设我有一个外部 srtream 和一个内部流,它们都使用并行流。事实证明,根据我的计算,如果首先完全并行地完成内部流,然后(如果且仅cpu 内核可用)执行外部流。我认为这适用于大多数人的情况。所以我的问题是:

Java 会先并行执行内部流,然后再处理外部流吗?如果是这样,它是在编译时还是在运行时做出决定?如果在运行时,JIT 是否足够聪明,能够意识到如果内部流确实有足够多的元素(例如数百个)而不是核心数(32),那么它肯定应该使用所有 32 个核心来处理移动到外部流的下一个元素之前的内部流;但是,如果元素的数量很少(例如 < 32),那么“也可以并行处理”来自“下一个”外部流的元素的元素是可以的。

最佳答案

也许下面的示例程序可以阐明这个问题:

IntStream.range(0, 10).parallel().mapToObj(i -> "outer "+i)
         .map(outer -> outer+"\t"+IntStream.range(0, 10).parallel()
            .mapToObj(inner -> Thread.currentThread())
            .distinct() // using the identity of the threads
            .map(Thread::getName) // just to be paranoid, as names might not be unique
            .sorted()
            .collect(Collectors.toList()) )
         .collect(Collectors.toList())
         .forEach(System.out::println);

当然,结果会有所不同,但我机器上的输出看起来与此类似:

outer 0 [ForkJoinPool.commonPool-worker-6]
outer 1 [ForkJoinPool.commonPool-worker-3]
outer 2 [ForkJoinPool.commonPool-worker-1]
outer 3 [ForkJoinPool.commonPool-worker-1, ForkJoinPool.commonPool-worker-4, ForkJoinPool.commonPool-worker-5]
outer 4 [ForkJoinPool.commonPool-worker-5]
outer 5 [ForkJoinPool.commonPool-worker-2, ForkJoinPool.commonPool-worker-4, ForkJoinPool.commonPool-worker-7, main]
outer 6 [main]
outer 7 [ForkJoinPool.commonPool-worker-4]
outer 8 [ForkJoinPool.commonPool-worker-2]
outer 9 [ForkJoinPool.commonPool-worker-7]

我们在这里可以看到,对于我的机器,有八个内核,七个工作线程正在参与工作,以利用所有内核,至于 common pool ,调用者线程也将参与工作,而不仅仅是等待完成。您可以在输出中清楚地看到 main 线程。

此外,您还可以看到外部流获得了完全的并行性,而一些内部流完全由单个线程处理。每个工作线程至少为外部流的一个元素做出贡献。如果将外部流的大小减少到核心数,您很可能会看到恰好有一个工作线程处理一个外部流元素,这意味着所有内部流完全按顺序执行。

但我使用了一个与核心数不匹配的数字,甚至不是它的倍数,来演示另一种行为。由于外部流处理的工作量不均匀,即一些线程只处理一项,其他线程处理两项,这些空闲工作线程执行工作窃取,为剩余外部元素的内部流处理做出贡献。

此行为背后有一个简单的基本原理。当外部流的处理开始时,它并不知道它将是一个“外部流”。它只是一个并行流,除了在其中一个函数开始另一个流操作之前对其进行处理之外,无法确定它是否是外部流。但是,将并行处理推迟到这个可能永远不会到来的时刻是没有意义的。

除此之外,我强烈反对您的假设“如果内部流首先完全并行完成,它的性能会更高 [...]”。对于典型的用例,我宁愿反过来期待它,阅读,期待一个完全按照它已经实现的方式去做的优势。但是,如前一段所述,无论如何都没有合理的方法来实现并行处理内部流的偏好。

关于java - 在考虑并行化外部流之前,是否会完全并行处理内部并行流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45570813/

相关文章:

java - 避免集群环境中 Spring Batch 作业的并发

java - 尽管系统时钟不准确,仍解析 ISO_LOCAL_TIME

java - 高对象复制时间导致 G1GC 长时间垃圾收集暂停

java ResultSet,使用MAX sql函数

python - Kotlin 替代 Python 协程的 yield 和 send

java - 将 Set<String> 中的所有值分配给带有流的 Map<String, String>

maven - Drools为什么不使用Java 8?

java - 如何在 GTalk、Skype 等 IM 应用中管理在线用户

java - 我怎样才能让输入将编辑文本中的输入文本添加到我的 ListView 中?在创建的添加按钮之上

java - 寻找多线程死锁的原因?