繁体   English   中英

如何确保java8流中的处理顺序?

[英]How to ensure order of processing in java8 streams?

我想处理XML java 对象内的列表。 我必须确保按顺序处理所有元素。

因此,我应该在我使用的每个stream上调用sequential吗? list.stream().sequential().filter().forEach()

或者只要我不使用并行性就可以使用流? list.stream().filter().forEach()

你问错了问题。 你是问sequentialparallel ,而要处理的项目,以便,所以你要问排序 如果您有一个有序的流并执行保证保持顺序的操作,那么该流是并行处理还是顺序处理无关紧要; 执行将维持秩序。

有序属性不同于并行与顺序。 例如,如果您在HashSet上调用stream() ,则流将是无序的,而在List上调用stream()返回有序流。 请注意,您可以调用unordered()来释放订购合同并可能提高性能。 一旦流没有排序,就无法重新建立排序。 (将无序流转换为有序流的唯一方法是调用sorted ,但是,结果顺序不一定是原始顺序)。

另请参阅java.util.stream包文档“订购”部分

为了确保在整个流操作中保持排序,您必须研究流的源、所有中间操作和终端操作的文档,以确定它们是否维护顺序(或源是否在第一个中具有排序)地方)。

这可能非常微妙,例如Stream.iterate(T,UnaryOperator)创建一个有序流而Stream.generate(Supplier)创建一个无序流。 请注意,您在问题中也犯了一个常见错误,因为forEach维护顺序。 如果要以有保证的顺序处理流的元素,则必须使用forEachOrdered

因此,如果您的问题中的list确实是java.util.List ,则其stream()方法将返回有序流,而filter不会更改排序。 因此,如果您调用list.stream().filter() .forEachOrdered() ,所有元素将按顺序依次处理,而对于list.parallelStream().filter().forEachOrdered()元素可能会并行处理(例如通过过滤器)但终端操作仍将按顺序调用(这显然会减少并行执行的好处)。

例如,如果您使用类似的操作

List<…> result=inputList.parallelStream().map(…).filter(…).collect(Collectors.toList());

整个操作可能受益于并行执行,但结果列表将始终按正确顺序排列,无论您使用并行流还是顺序流。

简而言之:

排序取决于源数据结构和中间流操作。 假设您使用的是List则应该对处理进行排序(因为filter不会改变此处的顺序)。

更多细节:

顺序 vs 并行 vs 无序:

文档

S sequential()
Returns an equivalent stream that is sequential. May return itself, either because the stream was already sequential, or because the underlying stream state was modified to be sequential.
This is an intermediate operation.
S parallel()
Returns an equivalent stream that is parallel. May return itself, either because the stream was already parallel, or because the underlying stream state was modified to be parallel.
This is an intermediate operation.
S unordered()
Returns an equivalent stream that is unordered. May return itself, either because the stream was already unordered, or because the underlying stream state was modified to be unordered.
This is an intermediate operation.

流排序:

文档

流可能有也可能没有定义的相遇顺序。 流是否具有遇到顺序取决于源和中间操作。 某些流源(例如 List 或数组)在本质上是有序的,而其他流源(例如 HashSet)则不是。 一些中间操作,例如 sorted(),可能会在原本无序的流上施加遇到顺序,而其他操作可能会呈现无序的有序流,例如 BaseStream.unordered()。 此外,某些终端操作可能会忽略遇到顺序,例如 forEach()。

如果流是有序的,则大多数操作都被限制为按元素遇到的顺序对元素进行操作; 如果流的源是一个包含[1, 2, 3]的List,那么执行map(x -> x*2)的结果一定是[2, 4, 6]。 但是,如果源没有定义的相遇顺序,则值 [2, 4, 6] 的任何排列都将是有效结果。

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

对于并行流,放宽排序约束有时可以实现更高效的执行。 如果元素的排序不相关,则可以更有效地实现某些聚合操作,例如过滤重复项 (distinct()) 或分组归约 (Collectors.groupingBy())。 类似地,本质上与遇到顺序相关的操作,例如 limit(),可能需要缓冲以确保正确排序,从而破坏了并行性的好处。 在流具有遇到顺序但用户并不特别关心该遇到顺序的情况下,使用 unordered() 显式对流进行排序可能会提高某些有状态或终端操作的并行性能。 然而,大多数流管道,例如上面的“块权重总和”示例,即使在排序约束下仍然有效地并行化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM