【问题标题】:Do limit and skip operations become stateless when unordered无序时限制和跳过操作是否变为无状态
【发布时间】:2016-05-07 06:04:50
【问题描述】:

我的问题很简单。 Java 流上的中间限制和跳过操作被标记为有状态操作 - 我假设是因为它们默认需要限制或跳过有序流上的前 n 个元素。

如果我通过调用 unordered() 方法或使用无序源使输入源流无序,我们是否可以有效地说这些操作可以被认为是无状态的,或者我在这里遗漏了什么?

【问题讨论】:

    标签: java java-stream stateless stateful


    【解决方案1】:

    不,limitskip 仍然是有状态的操作,因为元素的处理取决于其他元素的处理信息(即它们是否已被处理)。

    对于无序流,这些操作更容易实现,但这不会改变它们的状态性质。

    您可以通过简单地问自己来判断这一点:“是否可以通过仅查看元素而不其他任何内容(除了在启动整个流操作之前已知的不变信息)来为单个元素实现此操作?”

    【讨论】:

    • 啊,是的,我想一个过滤器可以在不关心任何其他元素的情况下进行过滤,而限制,需要知道已经处理了多少其他元素?
    【解决方案2】:

    我假设您的问题是关于并行流,因为在当前 Stream API 实现中顺序流不以任何方式使用排序。

    当前并行无序skip/limit 实现对每个并行任务使用大小为 128 的缓冲区,因此您可能会从源中读取比实际需要更多的元素。这样做是为了减少对共享原子变量的可能争用,这可能对低 Q 任务(每个元素处理非常快的任务)至关重要。所以要回答你的问题,不,无序的skip/limit 操作仍然是有状态的。

    您可以使用以下程序轻松检查:

    AtomicLong counter = new AtomicLong();
    IntStream.range(0, 1_000_000).parallel().unordered().filter(x -> true)
            .peek(x -> counter.incrementAndGet()).limit(1000).toArray();
    System.out.println(counter.get());
    

    它会打印实际从源中获取的元素数量。在我的四核系统上,此代码通常打印 1280 (128*10) 或 1408 (128*11),即使请求了 1000 个元素。

    【讨论】:

    • 我认为,这过于关注实现细节。而且流是否可能处理比必要更多的元素的问题与操作是否有状态的问题无关。
    • @Holger,我同意,但这取决于 OP 真正想知道的内容。
    • @TagirValeev 我对你的陈述有点困惑:“在当前的 Stream API 实现中,顺序流不以任何方式使用排序”。 findFirst() 和 findAny() 之类的操作呢?它们在不并行运行时的行为是否完全相同?另外,诸如 distinct() 之类的东西怎么样 - 如果存在顺序,这不会保留顺序,但如果源是无序的,即使按顺序运行,也不需要保留顺序?
    • @Tranquility,是的,连续的findFirst()findAny() 是一样的。还有forEachforEachOrdered。并且distinct() 在顺序模式下对无序流没有任何优势(尽管为distinct() 保留顺序似乎没有开销)。
    猜你喜欢
    • 2016-04-29
    • 2020-02-02
    • 2015-11-30
    • 1970-01-01
    • 2018-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    相关资源
    最近更新 更多