当前位置: 首页 > 知识库问答 >
问题:

Stream.reduce总是保持平行无序流的顺序

蒋奇
2023-03-14

我已经讨论了前面的几个问题,比如java stream中的遭遇顺序保存、Brian Goetz的回答,以及javadoc for stream。reduce()和java。util。流包javadoc,但我仍然无法理解以下内容:

以这段代码为例:

  public static void main(String... args) {
    final String[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
    System.out.println("Alphabet: ".concat(Arrays.toString(alphabet)));
    System.out.println(new HashSet<>(Arrays.asList(alphabet))
          .parallelStream()
          .unordered()
          .peek(System.out::println)
          .reduce("", (a,b) -> a + b, (a,b) -> a + b));
  }

为什么减少总是保持遭遇顺序?

  • 到目前为止,经过几十次运行,产量是相同的

共有3个答案

强保臣
2023-03-14

TLDR:。reduce()并不总是保持顺序,它的结果基于流拆分器的特性。

分离器

流的相遇顺序取决于流拆分器(前面提到的答案都没有)。

基于源流有不同的分裂器。您可以从这些集合的源代码中获得分裂器的类型。

HashSet-

ArrayDeque命令

ArrayList=有序

树集-

logicbig.com-订购logicbig.com-有状态vs无状态

此外,您可以应用. unorder()中间流操作,该操作指定流中的以下操作不应依赖于排序。

受拆分器和使用影响的流操作(大部分是有状态的)。unordered()方法包括:

  • 。findFirst()
  • 。限制()
  • 。跳过()
  • 。独特的

这些操作将根据流及其拆分器的顺序属性给出不同的结果。

。peek()方法不考虑排序,如果流并行执行,它将始终以无序方式打印/接收元素

.减少()

现在是终端。reduce()方法。中间操作。unordered()对拆分器的类型没有任何影响(正如@Eugene提到的)。但需要注意的是,它仍然和源拆分器中的一样。如果订购了源拆分器,则返回结果。如果源是的无序结果,则reduce()将被排序。reduce()将是无序的。

您正在使用新的HashSet

哈希集。reduce()-无序

"A","B","C","D","E","F" -> "ABCDEF"
"a","b","c","1","2","3","A","B","C" -> "a1Ab2Bc3C"
"Apple","Orange","Banana","Mango" -> "AppleMangoOrangeBanana"

TreeSet。reduce()-已排序

"A","B","C","D","E","F" -> "ABCDEF"
"a","b","c","1","2","3","A","B","C" -> "123ABCabc"
"Apple","Orange","Banana","Mango" -> "AppleBananaMangoOrange"

减少排序

"A","B","C","D","E","F" -> "ABCDEF"
"a","b","c","1","2","3","A","B","C" -> "abc123ABC"
"Apple","Orange","Banana","Mango" -> "AppleOrangeBananaMango"

您可以看到测试。reduce()仅对字母表源流进行操作可能会导致错误结论。

答案是。reduce()并不总是保持顺序,它的结果基于流拆分器的特性。

陆信瑞
2023-03-14

为了帮助解释这一点,我将把这个字符串的范围缩小到ABCD

并行流会把字符串分成两部分:ABCD,当我们后面去组合这些的时候,AB端的结果会是传入函数的第一个参数,而CD端的结果会是传入函数的第二个参数,这是不管这两者到底哪个先完成的。

无序运算符会影响流上的一些操作,比如一个限制操作,它不影响一个简单的减少

屠锦
2023-03-14

首先,unordered并不意味着真正的洗牌;它所做的一切都为流管道设置了一个标志——以后可以利用这个标志。

源元素的洗牌可能比流管道上的操作本身更昂贵,因此实现可能选择不这样做(就像在本例中一样)。

目前(测试和查看源代码)的jdk-8jdk-9-减少没有考虑到这一点。请注意,这在未来的构建或发布中很可能会改变。

另外,当你说unordered——你实际上是说你不关心这个顺序,返回相同结果的流并不违反这个规则。

例如,请注意这个问题/答案,它解释了findFirst例如(只是另一个终端操作)改变为在java-9中考虑无序,而不是java-8。

 类似资料:
  • 我已经讨论了一些相关问题,比如如何确保java8流中的处理顺序?,我仍然不完全清楚输出元素的顺序。因此,请澄清我的以下疑问。 我认为至少在理论上(或根据java规范),它可以按1、2、3、4、5、6、7、8以外的随机顺序打印。我说得对吗? 还有一个相关的问题——遭遇订单保存的决定是在执行的哪个点做出的?更准确地说,在执行开始之前,是否通过检查源、中间操作和终端操作的特性来评估整个流水线的订单特性?

  • 假设我有这样的代码: 输出是相同的线程名称,所以这里没有的好处--我的意思是有一个线程来完成所有的工作。 在内部有以下代码: 我理解强制属性如果“outer”流将是并行的(它们可能会阻塞),“outer”将不得不等待“flatmap”完成,反过来(因为使用了相同的公共池),但为什么总是强制这样做呢? 这是一个可以在以后的版本中改变的东西吗?

  • 问题内容: 假设我有以下代码: 输出是相同的线程名称,因此这里没有任何好处-我的意思是,只有一个线程可以完成所有工作。 里面是这段代码: 我知道如果“外部”流是并行的(可能会阻塞),则强制该属性,“外部”将不得不等待“ flatMap”完成,反之亦然(因为使用了相同的公共池),但是为什么 总是 强迫那个? 那是在以后的版本中 可能会 更改的事情之一吗? 问题答案: 有两个不同方面。 首先,只有一个

  • 问题内容: 以下代码以相同的插入顺序为我提供了输出。我阅读了Javadoc,他们甚至没有谈论插入顺序。有人可以帮助我获取正确的信息。 问题答案: 不,不是的。要保留插入顺序,请改用(javadoc)。 而且,现在优先于,因为它具有不必要的并发开销。(请参见HashMap和Hashtable之间的区别?。)

  • 问题内容: 是否可以保留“ IN”条件子句的顺序? 我在SO上发现了这个问题,但在他的示例中,OP已经有一个排序的“ IN”子句。 我的情况不同,’IN’子句的顺序是随机的: 我想按(45,2,445,12,789)顺序检索结果。我正在使用Oracle数据库。也许SQL中有一个属性,我可以将其与条件子句一起使用以指定保持子句的顺序。 问题答案: 除非您使用ORDER BY子句..否则不会有可靠的排

  • 问题内容: 我知道React可以异步并批量执行状态更新以优化性能。因此,在调用之后,您将永远无法相信要更新的状态。但是你可以信任的反应 更新相同的顺序状态被称为对 相同的组件? 不同的组件? 考虑在以下示例中单击按钮: 1. 在以下情况下,是否有可能 a为假而b为真 : 2. 在以下情况下,是否有可能 a为假而b为真 : 请记住,这些是我用例的极端简化。我意识到我可以以不同的方式进行操作,例如,在