Stream.spliterator对并行流的奇怪行为 [英] Strange behavior of Stream.spliterator for parallel streams

查看:196
本文介绍了Stream.spliterator对并行流的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用流分裂器直接进行我正在编写的库中的低级操作。最近,当我使用流分裂器并交错 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 。我将分裂器分开一次,所以它应该跳到一些中间位置。接下来我从中消耗一个元素并再次分割它。之后我打印所有剩余的元素。我希望我将从流尾部有几个连续的元素(可能是零元素,它也会很好)。但我得到的是 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆