【问题标题】:Does Stream.forEach() always work in parallel?Stream.forEach() 是否总是并行工作?
【发布时间】:2017-06-06 17:11:51
【问题描述】:

Aggregating with Streams 中,Brian Goetz 比较了使用 Stream.collect() 填充集合和使用 Stream.forEach() 填充集合,以及以下两个 sn-ps:

Set<String> uniqueStrings = strings.stream()
                                   .collect(HashSet::new,
                                            HashSet::add,
                                            HashSet::addAll);

还有,

Set<String> set = new HashSet<>();
strings.stream().forEach(s -> set.add(s));

然后他解释说:

关键 不同之处在于,对于 forEach() 版本,多个线程正在尝试访问单个结果 同时容器,而使用并行 collect(),每个线程都有自己的本地结果 容器,然后合并结果。

据我了解,只有在流是并行的情况下,多个线程才会在 forEach() 情况下工作。但是,在给出的示例中,forEach() 是在顺序流上运行的(不调用 parallelStream())。

那么,是 forEach() 总是并行工作,还是代码 sn-p 应该调用 parallelStream() 而不是 stream()。 (或者我错过了什么?)

【问题讨论】:

  • 顺便说一句,在示例中,collect() 也没有在并行流上被调用。 (?)

标签: java java-stream


【解决方案1】:

全文如下:

正如归约可以安全地并行化,只要组合函数是关联的并且没有干扰性副作用,Stream.collect() 的可变归约可以安全地并行化,前提是它满足某些简单的一致性要求(在collect() 的规范中进行了概述)。

然后你引用的内容:

主要区别在于,forEach() 版本中,多个线程尝试同时访问单个结果容器,而并行collect() 中,每个线程都有自己的本地结果容器,其结果被合并之后。

由于第一句清楚地谈到了并行化,我的理解是forEach()collect() 都是在并行流的上下文中谈到的。

【讨论】:

    【解决方案2】:

    不,如果流不并行,forEach() 不会并行化。我认为他为了讨论而简化了这个例子。

    作为证据,这段代码在 AbstractPipeline 类的评估方法中(从 forEach 调用)

     return isParallel()
                   ? terminalOp.evaluateParallel(this, sourceSpliterator(terminalOp.getOpFlags()))
                   : terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags()));
    

    【讨论】:

    • 感谢上帝。并行流意味着启动一个线程池,这将是一个超级昂贵的隐藏操作!
    猜你喜欢
    • 1970-01-01
    • 2012-02-17
    • 2014-11-11
    • 2012-06-27
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 2021-05-24
    • 1970-01-01
    相关资源
    最近更新 更多