【发布时间】:2015-03-31 07:55:51
【问题描述】:
环境:Ubuntu x86_64 (14.10),Oracle JDK 1.8u25
我尝试使用Files.lines() 的并行流,但我想.skip() 第一行(这是一个带有标题的CSV 文件)。因此我尝试这样做:
try (
final Stream<String> stream = Files.lines(thePath, StandardCharsets.UTF_8)
.skip(1L).parallel();
) {
// etc
}
但随后一列未能解析为 int...
所以我尝试了一些简单的代码。该文件的问题很简单:
$ cat info.csv
startDate;treeDepth;nrMatchers;nrLines;nrChars;nrCodePoints;nrNodes
1422758875023;34;54;151;4375;4375;27486
$
而且代码同样简单:
public static void main(final String... args)
{
final Path path = Paths.get("/home/fge/tmp/dd/info.csv");
Files.lines(path, StandardCharsets.UTF_8).skip(1L).parallel()
.forEach(System.out::println);
}
我系统地得到以下结果(好吧,我只运行了大约 20 次):
startDate;treeDepth;nrMatchers;nrLines;nrChars;nrCodePoints;nrNodes
我在这里错过了什么?
编辑 问题或误解似乎比这更根深蒂固(下面的两个示例是由 FreeNode 的 ##java 上的一个人编造的):
public static void main(final String... args)
{
new BufferedReader(new StringReader("Hello\nWorld")).lines()
.skip(1L).parallel()
.forEach(System.out::println);
final Iterator<String> iter
= Arrays.asList("Hello", "World").iterator();
final Spliterator<String> spliterator
= Spliterators.spliteratorUnknownSize(iter, Spliterator.ORDERED);
final Stream<String> s
= StreamSupport.stream(spliterator, true);
s.skip(1L).forEach(System.out::println);
}
打印出来:
Hello
Hello
呃。
@Holger 建议对于 ORDERED 而不是 SIZED 的任何流都会发生这种情况:
Stream.of("Hello", "World")
.filter(x -> true)
.parallel()
.skip(1L)
.forEach(System.out::println);
此外,它源于已经发生的所有讨论,即问题(如果是一个?)与.forEach()(如@SotiriosDelimanolis first pointed out)有关。
【问题讨论】:
-
我认为问题出在
forEach。 -
没有误解的余地——我简直不敢相信 JDK 中有这么明显的错误。我用十个元素尝试了你的代码,你猜怎么着,tenth 元素被跳过了。
-
您可以将第二个示例简化为
Stream.of("Hello", "World").filter(x->true) .parallel().skip(1).forEach(System.out::println);,因为任何没有可预测结果大小的流都可以。 -
Nicolai 和 Magnamag 的回答很好。我将添加那些被忽略的一些细节:Stream 实现将在可能的地方将 UNORDERED 特性反向传播到管道上。这使得像 orderedStream().sorted().forEach() 这样的计算能够优化排序。 (换句话说,想象
.forEach()真的是.unordered().forEach()的宏)。理解并行上下文中的排序是很困难的。我们都有多年的顺序偏见,导致我们对排序做出隐含的假设。 -
@Brian Goetz:它可能优化掉
sort,所以很遗憾它没有。即使使用.parallel().sorted().forEach(),终端消费者也会以任意顺序处理项目,但只有在执行后才会浪费资源先对项目进行排序。由于排序在顺序上下文中仍然很明显,因此在使用.sorted().forEach()时,难怪开发人员在被告知“.forEach()使 整个管道 无序”时感到惊讶。如果它真的一直如此,那就更好了。
标签: java parallel-processing java-8 java-stream