首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并行流中Stream.spliterator的奇怪行为

并行流中Stream.spliterator的奇怪行为
EN

Stack Overflow用户
提问于 2015-07-01 04:28:38
回答 2查看 781关注 0票数 10

我直接将流分配器用于我正在编写的库中的低级操作。最近,当我使用流分配器并交错tryAdvance/trySplit调用时,我发现了非常奇怪的行为。下面是一个简单的代码,它演示了这个问题:

代码语言:javascript
复制
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);
    }
}

输出是

代码语言:javascript
复制
5
6
9

正如您所看到的,在平面映射之后,我应该得到从19的连续数字的有序流。我拆分了一次分配器,所以它应该跳到某个中间位置。接下来,我从它中使用一个元素,然后再分割它一次。在此之后,我将打印所有剩余的元素。我希望我会从流尾中得到几个连续的元素(可能是零元素,也会很好)。然而,我得到的是56,然后突然跳到9

我知道,目前在JDK中,分配器并不是以这种方式使用的:它们总是在遍历之前拆分。然而,官方的文档并没有明确禁止在tryAdvance之后调用trySplit

当我使用直接从集合、数组、生成源等创建的分割器时,从来没有注意到这个问题。只有当分割器是从具有中间flatMap的并行流中创建时,才能观察到这个问题。

所以问题是:我是碰到了错误,还是明确禁止在某个地方以这种方式使用分配器?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-07-01 06:55:19

AbstractWrappingSpliterator和company的来源中可以看出,当您使用tryAdvance时,flatMap (4,5,6)的输出被缓冲,然后4被消耗掉(5,6)留在缓冲区中。然后,trySplit正确地将(7,8)除以新的Spliterator,留下旧的9,而缓冲的(5,6)与旧的Spliterator保持在一起。

所以在我看来这就像个窃听器。它应该将缓冲区交给新的Spliterator,或者返回null,如果缓冲区不是空的,则拒绝拆分。

票数 5
EN

Stack Overflow用户

发布于 2016-02-08 16:50:03

这种行为被官方认为是一个bug (请参阅JDK-8148838),由我修复,并被推入JDK-9主干(参见变化集)。可悲的是,我最初的修补程序实际上在flatMap之后修复了拆分(参见韦布列夫),但是这个修补程序被拒绝了,因为这种场景(在tryAdvance()之后使用trySplit() )被认为是不常见的,也是不鼓励的。目前已被接受的解决方案是在前进之后禁用WrappingSpliterator拆分,这足以解决问题。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31152557

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档