Java 流并行跳过-链式流方法的顺序有什么不同吗?
vsJava 流并行跳过-链式流方法的顺序有什么不同吗?,java,java-8,java-stream,Java,Java 8,Java Stream,vs stream.parallel().skip(1) 这是关于Java8流的。 这两个都跳过了第一行/条目吗 例如: stream.skip(1).parallel() 今天早些时候,我有时会在lambda表达式中得到标题行“a,b,c”。这是一个惊喜,因为我本以为已经跳过了。现在我无法使该示例工作,即,我无法获得lambda表达式中的头行。所以我现在很困惑,也许是其他因素影响了这种行为。当然,这只是一个例子。在现实世界中,消息是从CSV文件读取的。该消息是该CSV文件的完整内容。是
stream.parallel().skip(1)
这是关于Java8流的。这两个都跳过了第一行/条目吗 例如:
stream.skip(1).parallel()
今天早些时候,我有时会在lambda表达式中得到标题行“a,b,c”。这是一个惊喜,因为我本以为已经跳过了。现在我无法使该示例工作,即,我无法获得lambda表达式中的头行。所以我现在很困惑,也许是其他因素影响了这种行为。当然,这只是一个例子。在现实世界中,消息是从CSV文件读取的。该消息是该CSV文件的完整内容。是,但是skip(n)
速度较慢,因为n
在并行流中更大
以下是API注释:
虽然skip()
通常是顺序流管道上的一种廉价操作,但在有序并行管道上,它可能非常昂贵,尤其是对于n
的大值,因为skip(n)
被约束为不仅跳过任何n
元素,而且跳过相遇顺序中的第一个n
元素。使用无序流源(例如generate(Supplier)
)或删除BaseStream的排序约束。如果您的情况语义允许,无序()
可能会导致并行管道中的skip()
显著加速。如果需要与遭遇顺序保持一致,并且并行管道中的skip()
性能或内存利用率较差,则切换到使用BaseStream的顺序执行。sequential()
可能会提高性能
因此,从本质上讲,如果您希望使用skip()
获得更好的性能,请不要使用并行流或无序流
至于它似乎不适用于并行流,也许你真的看到元素不再有序了?例如,此代码的输出:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.concurrent.atomic.AtomicLong;
public class Test010 {
public static void main(String[] args) {
String message =
"a,b,c\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n1,2,3\n4,5,6\n7,8,9\n";
try(BufferedReader br = new BufferedReader(new StringReader(message))){
AtomicLong cnt = new AtomicLong(1);
br.lines().parallel().skip(1).forEach(
s -> {
System.out.println(cnt.getAndIncrement() + "->" + s);
}
);
}catch (IOException e) {
e.printStackTrace();
}
}
}
是
是你呢?
怎么 这是非常好的,因为
forEach
不会在并行流中强制执行遭遇顺序。如果您希望它强制执行遭遇顺序,请使用顺序流(或者使用forEachOrdered
,以便您的意图显而易见)
如何是
你呢
实际上,一个问题中有两个问题,第一个问题是它是否会在编写
stream.parallel().skip(1)
或stream.skip(1.parallel()
时产生影响,第二个问题是其中一个或两个元素是否总是跳过第一个元素。另见
第一个答案是没有区别,因为指定.sequential()
或.parallel()
执行策略会影响整个流管道,当然,无论您将其放置在调用链的何处,除非您指定多个相互矛盾的策略,在这种情况下,最后一个策略获胜
因此,在任何一种情况下,您都在请求并行执行,这可能会影响跳过
操作的结果,这是第二个问题的主题
答案并不是那么简单。如果流首先没有定义的相遇顺序,则可能会跳过任意元素,这是因为没有“first”元素,即使在源代码上迭代时可能会首先遇到元素
如果您有一个有序流,skip(1)
应该跳过第一个元素,但这是最近才制定的。如中所述,链接无序终端操作会影响早期实现中的跳过
操作,并且不确定这是否是有意的,如中所示,这恰好与您的代码相近;显然,跳过第一行是一种常见的情况
最后一句话是,早期JRE的行为是一个bug,在有序流上的skip(1)
应该跳过第一个元素,即使流管道并行执行且终端操作无序。将jdk1.8.0_60命名为第一个固定版本,我可以对此进行验证。因此,如果在较旧的实现上使用,则在使用.parallel()
和无序的.forEach(…)
终端操作时,可能会遇到跳过不同元素的流。如果实现偶尔跳过预期的元素,这并不矛盾,这就是多线程的不可预测性
因此,答案仍然是
stream.parallel().skip(1)
和stream.skip(1).parallel()
具有相同的行为,即使在早期版本中使用时也是如此,因为当与无序的终端操作(如forEach
一起使用时,这两种行为同样不可预测。他们应该总是跳过具有有序流的第一个元素,当与1.8.0_60
或更高版本一起使用时,他们应该跳过。您是否尝试过这两个元素来找出答案?您的问题的答案是肯定的。阅读“我尝试了第一个选项”,在我看来(实际上我非常确定)我没有跳过第一行/条目。我只是跳过了一些随机的条目。也许你是无意中发现的。检查您使用的是哪一个Java版本。@Andrew尝试这两个版本可能会证明它们是不同的,但确定它们是否必须相同是没有用的,这正是OP所要求的。他的意思不是“有时它可能会产生相同的结果”,而是“它必须产生相同的结果。”而尝试它并没有真正的帮助;您必须符合规格。谢谢,但我不太在乎性能。我在乎是跳过第一个条目还是某个随机条目。@peter.petrov这不是跳过一个随机条目。它仍然跳过相同的条目。你能提供一个问题的MCVE吗?是的,你的例子非常有限。这个问题是关于遭遇顺序的。怎么样
Stream.of("Hello", "How", "Are", "You?")
.parallel()
.skip(1)
.forEach(System.out::println);
Stream.of("Hello", "How", "Are", "You?")
.skip(1)
.forEachOrdered(System.out::println);