簡體   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