繁体   English   中英

Java并行流只使用一个线程?

[英]Java parallel stream using only one thread?

我正在使用最新的Java 8 lambdas和并行流来处理数据。 我的代码如下:

ForkJoinPool forkJoinPool = new ForkJoinPool(10);
List<String> files = Arrays.asList(new String[]{"1.txt"}); 
List<String> result = forkJoinPool.submit(() ->
    files.stream().parallel()
        .flatMap(x -> stage1(x)) //at this stage we add more elements to the stream
        .map(x -> stage2(x))
        .map(x -> stage3(x))
        .collect(Collectors.toList())
).get();

流以一个元素开始,但在第二个阶段添加更多元素。 我的假设是这个流应该并行运行,但在这种情况下只使用一个工作线程。

如果我从2个元素开始(即我将第二个元素添加到初始列表中),则会生成2个线程来处理流等等......如果我没有将流显式提交给ForkJoinPool,也会发生这种情况。

问题是:它是记录在案的行为还是可能在实施中发生变化? 有没有办法控制这种行为,并允许更多的线程,无论初始列表?

您可以尝试使用简单反应的 LazyFutureStream或EagerFutureStream Stream实现。 两个Streams都会为每个处理单元创建一个CompletableFuture,每个处理单元都可以在一个单独的线程上执行。 可能会导致更高效的处理(取决于您的实际用例和资源)。

例如

 LazyFutureStream.parallelBuilder(10)
                .of("1.txt")
                .flatMap(x -> stage1(x)) 
                .map(x -> stage2(x))
                .map(x -> stage3(x))
                .collect(Collectors.toList());

要么

EagerFutureStream.parallelBuilder(10)
                .of("1.txt")
                .flatMap(x -> stage1(x)) 
                .map(x -> stage2(x))
                .map(x -> stage3(x))
                .collect(Collectors.toList());

您观察的是特定于实现的行为,而不是指定的行为。

当前的JDK 8实现查看最外层流的Spliterator ,并将其用作拆分并行工作负载的基础。 由于该示例在原始源流中只有一个元素,因此无法拆分,并且该流运行单线程。 这适用于常见(但绝不仅限于) flatMap返回零,一个或仅少数元素的情况,但在返回大量元素的情况下,它们都是按顺序处理的。 实际上, flatMap函数返回的流被强制进入顺序模式。 参见ReferencePipeline.java的第270行。

“显而易见”的事情是使这个流并行,或者至少不强制它是顺序的。 这可能会也可能不会改善。 最有可能的是它会改善一些事情,但会使其他事情变得更糟。 这里肯定要求更好的政策,但我不确定它会是什么样子。

另请注意,用于强制并行流在您选择的fork-join池中运行的技术,通过向其提交运行管道的任务,也是特定于实现的行为。 它在JDK 8中以这种方式工作,但它可能在将来发生变化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM