当前位置: 首页 > 面试题库 >

并行flatMap总是顺序的

狄雅珺
2023-03-14
问题内容

假设我有以下代码:

 Collections.singletonList(10)
            .parallelStream() // .stream() - nothing changes
            .flatMap(x -> Stream.iterate(0, i -> i + 1)
                    .limit(x)
                    .parallel()
                    .peek(m -> {
                        System.out.println(Thread.currentThread().getName());
                    }))
            .collect(Collectors.toSet());

输出是相同的线程名称,因此这里没有任何好处parallel-我的意思是,只有一个线程可以完成所有工作。

里面flatMap是这段代码:

result.sequential().forEach(downstream);

我知道sequential如果“外部”流是并行的(可能会阻塞),则强制该属性,“外部”将不得不等待“
flatMap”完成,反之亦然(因为使用了相同的公共池),但是为什么 总是 强迫那个?

那是在以后的版本中 可能会 更改的事情之一吗?


问题答案:

有两个不同方面。

首先,只有一个流水线是顺序的或并行的。在内流处选择顺序还是并行无关紧要。请注意,downstream您在引用的代码片段中看到的使用者代表整个后续流管道,因此在您的代码中(以结尾).collect(Collectors.toSet());,该使用者最终会将结果元素添加到Set不是线程安全的单个实例中。因此,与单个使用者并行处理内部流将破坏整个操作。

如果外部流被拆分,则引用的代码可能会与添加到不同集合的不同使用者同时调用。这些调用中的每个调用都会处理外部流的不同元素,以映射到不同的内部流实例。由于您的外部流仅包含一个元素,因此无法拆分。

这已经实现了,这也是为什么flatMap()之后的filter()在Java流中“不完全”惰性的原因?问题,如forEach内部流所称,它将把所有元素传递给下游使用者。如该答案所示,支持懒惰和子流拆分的替代实现是可能的。但这是实现它的根本不同的方法。Stream实现的当前设计主要根据使用者组成来工作,因此最后,源拆分器(以及从中拆分的源拆分器)ConsumertryAdvance或中接收代表整个流管道的forEachRemaining。相比之下,链接答案的解决方案确实进行了分隔器组合,从而产生了新的Spliterator委托给源分割器。我以为,这两种方法都有优势,而且我不确定在相反方向工作时OpenJDK实现会损失多少。



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

  • 我已经讨论了前面的几个问题,比如java stream中的遭遇顺序保存、Brian Goetz的回答,以及javadoc for stream。reduce()和java。util。流包javadoc,但我仍然无法理解以下内容: 以这段代码为例: 为什么减少总是保持遭遇顺序? 到目前为止,经过几十次运行,产量是相同的

  • 我正在实现一个分页器(在Java),它应该允许并行访问。 我有以下测试用例(测试在Groovy中,带有Spock): 此testcase失败,出现以下错误: 拆分器具有 当我不使用并行时,代码可以工作。所以我不理解: 如果设置了,流框架是否应该保证顺序,并且应该在使用并行生成的块时对结果进行排序?如果是,为什么不在我的情况下排序? 还是我的实现中有错误,必须按照给定的顺序拆分?(当前我在打开页面的

  • 我们有一个基于quartz的调度程序应用程序,每分钟运行大约1000个作业,这些作业平均分布在每分钟的几秒钟内,即每秒大约16-17个作业。理想情况下,这16-17个作业应该同时触发,但是我们的第一条语句,它只是记录执行的时间,任务的execute方法调用得很晚。假设从05:00到05:04,我们每分钟安排1000个工作。因此,理想情况下,计划在05:03:50的作业应该在05:03:50记录ex

  • 问题内容: 我们有一个基于石英的调度程序应用程序,该应用程序每分钟运行约1000个作业,每分钟的秒数均匀分布,即每秒约16-17个作业。理想情况下,这16-17个作业应同时触发,但是该作业的execute方法的第一个语句(仅记录执行时间)非常晚。例如,假设我们从05:00到05:04每分钟安排1000个作业。因此,理想情况下,计划在05:03:50进行的作业应该在05:03:50记录了execut

  • 问题内容: 我想澄清这一点,因为文档对此不太清楚。 问题1: 是按顺序还是并行处理所有承诺?或者,更具体地说,它相当于运行像 或者是一些其他类型的算法的所有,,,,,等是被称为在同一时间(并行)和结果尽快返回所有的决心(或一个不合格品)? 问题2: 如果并行运行,是否有方便的方法可以依次运行可迭代程序? 注意 :我不想使用Q或Bluebird,而是要使用所有本机ES6规范。 问题答案: 正在执行的