搜索不一致行为 java-8 流的示例?

Posted

技术标签:

【中文标题】搜索不一致行为 java-8 流的示例?【英文标题】:search for example of inconsistent behavior java-8 stream? 【发布时间】:2017-12-10 05:29:30 【问题描述】:

在 java 8 文档 (doc order stream) 中,可以看到:

如果 [a stream] 没有排序,重复执行可能会产生不同的 结果。

我的问题很简单:有没有一种简单的方法可以在一个小单元测试中说明这一事实(可能使用 HashMap 或类似的东西)?

[编辑] 全文在这里:

对于顺序流,遇到顺序的存在与否不会影响性能,只会影响确定性。如果流是有序的,在相同的源上重复执行相同的流管道将产生相同的结果;如果没有排序,重复执行可能会产生不同的结果。

因此,我的问题是关于严格顺序而不是并行执行。我要问的就是这个案子。

【问题讨论】:

见here 正如我在 cmets 中解释的那样,java 文档明确给出了这种严格顺序执行而不是并行执行的行为:“对于顺序流,遇到顺序的存在或不存在不会影响性能,仅" si 我的问题是关于这个案子而不是平行案 链接答案的解释仍然成立。无论是顺序的还是并行的,流都不会乱序排列元素,它只会在有性能优势的情况下尝试利用无序性。因此,即使文档表明在顺序情况下不会有性能差异,这意味着在顺序情况下与当前实现不会有行为差异。正如链接的答案所说。而“可能产生不同的结果”并不意味着“会产生不同的结果”。 【参考方案1】:

显而易见的答案是,无论何时使用unordered,都会得到不同的结果。例如使用这个:

int first = Arrays.asList(1, 2, 3, 4).stream()
           .unordered()
           .parallel()
           .findFirst()
           .get();
System.out.println(first);

应该产生一个总是1的结果。因为流是无序的,所以[1,2,3,4]之外的任何结果都是可能的。

在 java-8 中这是不正确的,流管道不考虑 unordered

    @Override
    public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
                                     Spliterator<P_IN> spliterator) 
        return new FindTask<>(this, helper, spliterator).invoke();
    

但是在 java-9 中情况发生了变化:

    @Override
    public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
                                     Spliterator<P_IN> spliterator) 
        // This takes into account the upstream ops flags and the terminal
        // op flags and therefore takes into account findFirst or findAny
        boolean mustFindFirst = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags());
        return new FindTask<>(this, mustFindFirst, helper, spliterator).invoke();
    

所以在 java-9 下多次运行相同的代码会产生不同的结果。

有些操作已经是unordered,例如Stream#generateStream#forEach

【讨论】:

我非常理解这样的示例如何在多次执行中产生不同的结果,因为它使用并行执行。但是据我了解有关此问题的 java 8 文档,即使在顺序而不是并行执行中也可能出现这种情况。那是我的问题。不清楚,但我想要一个仅按顺序执行的行为示例。 @LyxtheLyxos 据我了解并尝试过 - 目前这是不可能的。流不会对无序的顺序处理进行任何随机化。他们可能在未来......这就是规范是这样的原因 - 它为更改敞开大门 @LyxtheLyxos 与流无关,但随机化发生在其他地方。例如在 jdk-9 中的不可变集合中。 Map.of...Set.of 确实 具有随机化模式,因此条目在内部以不同的顺序排列。【参考方案2】:

Stream#forEach 的文档已经说如下:

此操作的行为明确不确定。对于并行流管道,此操作不保证尊重流的遇到顺序,因为这样做会牺牲并行性的好处。

所以应该通过以下测试:

List<Integer> ordered = Arrays.asList(1, 2, 3, 4);
List<Integer> unordered = new CopyOnWriteArrayList<>();

ordered.stream().parallel().forEach(unordered::add);

assertThat(unordered, not(equalTo(ordered)));

并且操作Stream#findAny 也是非确定性的

【讨论】:

我的评论与上述相同,我非常理解这样的示例如何在多次执行中产生不同的结果,因为它使用并行执行。但是据我了解有关此问题的 java 8 文档,即使在顺序而不是并行执行中也可能出现这种情况。那是我的问题。不清楚,但我想要一个仅按顺序执行的行为示例。 @LyxtheLyxos 你好,你可以看这里,还有一个问题,里面有很多链接,也许你很有趣***.com/questions/44954433/… @LyxtheLyxos 我认为它不能在顺序流中完成,因为unordered 不是shuffle,它不能在单个thread 中完成。 @holi-java 好吧,数据可以在内部以某种方式随机化......但无论你怎么看都会很昂贵 @Eugene 是的,我认为OP误解了ordering部分,它只描述了一段代码,就像重复调用source.stream().collect(toList())一样,结果顺序取决于source是否是或ordered,而不是unordered 操作。

以上是关于搜索不一致行为 java-8 流的示例?的主要内容,如果未能解决你的问题,请参考以下文章

如何解释 visualvm cpu 示例和从中创建的快照之间的不一致?

Scalajs, js.Dictionary 不一致的行为

LSUIElement 的行为与 activateIgnoringOtherApps 不一致

iOS 14 中设备之间的小部件行为不一致

NSManagedObject 子类之间看似不一致的行为

Oracle 不一致的查询性能行为