Stream.spliterator对并行流的奇怪行为 [英] Strange behavior of Stream.spliterator for parallel streams
问题描述
我正在使用流分裂器直接进行我正在编写的库中的低级操作。最近,当我使用流分裂器并交错 tryAdvance / trySplit
调用时,我发现了非常奇怪的行为。这是一个演示问题的简单代码:
I'm using the stream spliterator directly for the low-level operations in the library I'm writing. Recently I discovered very weird behavior when I take the stream spliterator and interleave tryAdvance/trySplit
calls. Here's a simple code which demonstrates the problem:
import java.util.Arrays;
import java.util.Spliterator;
public class SpliteratorBug {
public static void main(String[] args) {
Integer[][] input = { { 1 }, { 2, 3 }, { 4, 5, 6 }, { 7, 8 }, { 9 } };
Spliterator<Integer> spliterator = Arrays.stream(input).parallel()
.flatMap(Arrays::stream).spliterator();
spliterator.trySplit();
spliterator.tryAdvance(s -> {});
spliterator.trySplit();
spliterator.forEachRemaining(System.out::println);
}
}
输出
5
6
9
正如您所看到的,在平面映射之后,我应该从 1
到 9 $的连续数字的有序流C $ C>。我将分裂器分开一次,所以它应该跳到一些中间位置。接下来我从中消耗一个元素并再次分割它。之后我打印所有剩余的元素。我希望我将从流尾部有几个连续的元素(可能是零元素,它也会很好)。但我得到的是
5
和 6
,然后突然跳到 9
。
As you can see, after flat-mapping I should get the ordered stream of consecutive numbers from 1
to 9
. I split the spliterator once, so it should jump to some intermediate location. Next I consume an element from it and split it one more time. After that I print all the remaining elements. I expect that I will have several consecutive elements from the stream tail (probably zero elements, it would also be fine). However what I get is 5
and 6
, then sudden jump to 9
.
我知道目前在JDK分裂器中没有使用这种方式:它们总是在遍历之前分裂。但官方的文档并未明确禁止调用 trySplit
在 tryAdvance
之后。
I know that currently in JDK spliterators are not used this way: they always split before the traversal. However official documentation does not explicitly forbid to call the trySplit
after tryAdvance
.
当我使用spliterator时从未发现过这个问题直接从集合,数组,生成的源等创建。仅当spliterator是从具有中间 flatMap
的并行流创建时才会被观察到。
The problem was never observed when I use spliterator created directly from collection, array, generated source, etc. It's observed only if the spliterator was created from the parallel stream which had the intermediate flatMap
.
所以问题是:我是否遇到了这个错误,或者是否明确禁止以某种方式使用分裂器?
So the question is: did I hit the bug or it's explicitly forbidden somewhere to use the spliterator in this way?
推荐答案
从 AbstractWrappingSpliterator
和公司的来源中可以看到,当你 tryAdvance
时,输出 flatMap
(4,5,6)得到缓冲,然后4消耗,留下(5,6)缓冲区。然后 trySplit
正确地将(7,8)拆分为新的 Spliterator
在旧的一个中留下9但是缓冲(5) ,6)使用旧的 Spliterator
。
From what I can see from the source of AbstractWrappingSpliterator
and company, when you tryAdvance
, the output of flatMap
(4,5,6) gets buffered and then 4 gets consumed leaving (5,6) in the buffer. Then trySplit
correctly splits off (7,8) to the new Spliterator
leaving 9 in old one but the buffered (5,6) stay with the old Spliterator
.
所以这看起来像是一个bug。它应该将缓冲区关闭到新的 Spliterator
或返回 null
,如果缓冲区不为空,则拒绝拆分。
So this looks like a bug to me. It should either hand the buffer off to the new Spliterator
or return null
and refuse to split if the buffer is not empty.
这篇关于Stream.spliterator对并行流的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!