【发布时间】:2015-12-17 18:23:50
【问题描述】:
以下代码片段是获取目录列表、对每个文件调用提取方法并将生成的药物对象序列化为 xml 的方法的一部分。
try(Stream<Path> paths = Files.list(infoDir)) {
paths
.parallel()
.map(this::extract)
.forEachOrdered(drug -> {
try {
marshaller.write(drug);
} catch (JAXBException ex) {
ex.printStackTrace();
}
});
}
这是完全相同的代码,执行完全相同的操作,但使用普通的 .list() 调用来获取目录列表并在结果列表上调用 .parallelStream()。
Arrays.asList(infoDir.toFile().list())
.parallelStream()
.map(f -> infoDir.resolve(f))
.map(this::extract)
.forEachOrdered(drug -> {
try {
marshaller.write(drug);
} catch (JAXBException ex) {
ex.printStackTrace();
}
});
我的机器是四核 MacBook Pro,Java v 1.8.0_60(内部版本 1.8.0_60-b27)。
我正在处理 ~ 7000 个文件。 3 次运行的平均值:
第一个版本:
.parallel():20 秒。没有.parallel():41 秒
第二版:
.parallelStream():12 秒。 .stream():41 秒。
考虑到从流中读取并执行所有繁重工作的extract 方法和执行最终写入的write 调用,并行模式下的这8 秒似乎是一个巨大的差异。
【问题讨论】:
-
没有parallelStream你的代码表现如何?
-
gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html "目前,基于 JDK IO 的 Stream 源(例如 BufferedReader.lines())主要面向顺序使用,在元素到达时一个接一个地处理。"跨度>
-
目录流事先不知道它的大小,因此无法平衡工作负载拆分。正如您自己所说,是
extract完成了繁重的工作,而不是读取目录,因此将目录单线程完全读取到内存中并对生成的数组执行并行操作,该数组具有已知的大小,很多更高效。 -
在每个 Stream 上调用
spliterator().characteristics()返回的标志是值得的。对我来说(在 Windows 7 64 位上),第一个只返回DISTINCT,而第二个返回ORDERED|SIZED|IMMUTABLE|SUBSIZED。 -
“根本玩得不好”,你真正的意思是“从无限的、延迟生成的源中有效地提取并行性比从像数组或集合这样的物化有限源中提取并行性更难",这反映在库性能中。
标签: java parallel-processing java-8 nio java-stream