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

并行流上的iterator()保证遇到顺序?

姚烨
2023-03-14
Stream.of(a, b, c).parallel().map(Object::toString).iterator();

返回的迭代器是否保证按该顺序提供值 abc

我知道toArray()collect()保证集合的值顺序正确。此外,我并不是在问如何从迭代器生成流。

共有3个答案

钮边浩
2023-03-14

到目前为止,我发现最接近保证的是java.util.stream包文档中的以下语句:

除了被标识为显式不确定的操作(如findAny())之外,流是顺序执行还是并行执行都不会改变计算的结果。

可以说,iterator()生成一个以不同顺序迭代Iterator将是“结果的变化”,就像生成一个包含不同顺序元素的List将用于Collection()一样。

吕利
2023-03-14

< code>Stream.of方法用于从不关联的值创建流,返回一个有序的流。

返回元素为指定值的有序流。

根据 Java.util.stream 的软件包“边效应”部分:

IntStream.range(0,5).parallel()。地图(x-

这意味着< code>parallel()和< code>map()保留流是否是顺序的/有序的。

我已经跟踪了Stream的实现。的创建到名为ReferencePipeline的类。

@Override
public final Iterator<P_OUT> iterator() {
    return Spliterators.iterator(spliterator());
}

该实现的iterator()方法遵从Spliterator。iterator(),其代码仅依赖于Spliterator's的tryAdvance方法来适应0.05 iterator接口,并且不会更改任何流特征:

public static<T> Iterator<T> iterator(Spliterator<? extends T> 
    spliterator) {
    Objects.requireNonNull(spliterator);
    class Adapter implements Iterator<T>, Consumer<T> {
        boolean valueReady = false;
        T nextElement;

        @Override
        public void accept(T t) {
            valueReady = true;
            nextElement = t;
        }

        @Override
        public boolean hasNext() {
            if (!valueReady)
                spliterator.tryAdvance(this);
            return valueReady;
        }

        @Override
        public T next() {
            if (!valueReady && !hasNext())
                throw new NoSuchElementException();
            else {
                valueReady = false;
                return nextElement;
            }
        }
    }

    return new Adapter();
}

总之,是的,顺序是有保证的,因为< code>Stream.of创建了一个“顺序有序流”,并且上面使用的任何操作:< code>parallel、< code>map或< code>iterator都不会改变特征。事实上,< code>iterator使用底层流< code>Spliterator来迭代流元素

叶声
2023-03-14

这是规范中的一个疏忽。如果一个流有一个定义好的相遇顺序,那么它的目的就是让它的迭代器按照相遇顺序产生元素。如果流没有定义遇到顺序,迭代器当然会以某种顺序产生元素,但是顺序不会被定义。

我已经提交了错误JDK-8194952来跟踪规范的更改。

看起来其他人已经爬取了足够多的实现,以表明它确实会按遇到顺序生成元素。此外,我们的流测试依赖于此属性。例如,toList收集器的测试断言列表中的元素以与从流的Iterator获得的顺序相同的顺序存在。因此,依赖于此行为可能是安全的,即使它还没有正式指定。

 类似资料:
  • 我有一个记录课程: 我创建了一个包含很多记录的大列表。只有第二个和第五个值,即i/10000和i,稍后分别由getter使用。 请注意,前10000条记录的类别2为0,接下来的10000条记录的类别1等,而值1按顺序为0-114999。 我创建了一个既并行又排序的流。 我有一个ForkJoinPool,它维护8个线程,这是我电脑上的内核数。 我使用这里描述的技巧将流处理任务提交给我自己的,而不是常

  • 是否有任何保证在顺序和有序流上的操作是按遇到顺序处理的? 我是说,如果我有这样的代码: 是否可以保证它将按照生成范围的遇到顺序执行myFunction()调用? 我找到了Stream类的JavaDocs草案,它明确地说明了以下内容: 对于顺序流管道,如果管道源具有已定义的遇到顺序,则所有操作都按照管道源的遇到顺序执行。 但是它没有提到顺序流,这个例子是针对并行流的(我的理解是,顺序流和并行流都是正

  • 问题内容: Javadoc 表示(重点是我): 该操作的行为明确地是不确定的。 对于并行流管道,此操作不能保证遵守流的遇到顺序 ,因为这样做会牺牲并行性的好处。对于任何给定的元素,可以在库选择的任何时间和线程中执行操作。如果操作访问共享状态,则它负责提供所需的同步。 Java 9 Early Access Javadoc中提供了相同的文本。 第一句话(“明确地不确定”)表明(但未明确说明)此方法未

  • 我想在Java对象中处理列表。我必须确保处理所有的元素,以便我收到他们。 因此,我是否应该对我使用的每个调用? 或者,只要不使用并行性,只使用流就足够了吗?

  • 的Javadoc表示(强调是我的): 此操作的行为显式不确定。对于并行流管道,此操作不能保证尊重流的相遇顺序,因为这样做会牺牲并行性的好处。对于任何给定的元素,操作可以在库选择的任何时间和线程中执行。如果操作访问共享状态,则它负责提供所需的同步。 同样的文本也出现在Java9早期访问Javadoc中。 如果forEach不保留遭遇顺序,则会引入bug。在报告针对NetBeans的bug之前,我想知

  • 问题内容: 我有大量数据,并且想要调用缓慢但干净的方法,而不是调用带有第一个结果的副作用的快速方法。我对中间结果不感兴趣,所以我不想收集它们。 明显的解决方案是创建并行流,进行慢速调用,再次使流顺序进行,然后进行快速调用。问题是,所有代码都在单个线程中执行,没有实际的并行性。 示例代码: 如果我删除,代码将按预期执行,但是很明显,非并行操作将在多个线程中调用。 您能推荐一些有关这种行为的参考,或者