搜索不一致行为 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#generate
和Stream#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 示例和从中创建的快照之间的不一致?