我正在研究java 8并行流并且想要在并行流中打印元素是一些顺序(比如插入顺序,逆序或顺序)。
我尝试了以下代码:
class OopsExceptionHandler : ExceptionHandler
{
public override void HandleCore(ExceptionHandlerContext context)
{
context.Result = new TextPlainErrorResult//you have to create this class
{
Request = context.ExceptionContext.Request,
Content = "Oops! Sorry! Something went wrong." +
"Please contact support@contoso.com so we can try to fix it."
};
}
}
对于这两个,我得到了相同的输出如下:
System.out.println("With forEachOrdered:");
listOfIntegers
.parallelStream()
.forEachOrdered(e -> System.out.print(e + " "));
System.out.println("");
System.out.println("With Sequential:");
listOfIntegers.parallelStream()
.sequential()
.forEach(e -> System.out.print(e + " "));
从api文档中,我可以看到:
forEachOrdered - >这是终端操作。
和
顺序 - >这是一个中间操作。
所以我的问题是哪一个更好用? 在哪种情况下,一个应该优先于其他?
答案 0 :(得分:4)
listOfIntegers.parallelStream().sequential().forEach()
创建了一个并行Stream
,然后将其转换为顺序Stream
,因此您也可以改为使用listOfIntegers.stream().forEach()
,并获得顺序Stream
首先。
listOfIntegers.parallelStream().forEachOrdered(e -> System.out.print(e + " "))
对并行Stream
执行操作,但保证元素将按Stream
的遭遇顺序使用(如果Stream
有定义的遭遇订购)。但是,它可以在多个线程上执行。
我没有看到使用listOfIntegers.parallelStream().sequential()
的原因。如果您想要顺序Stream
,为什么要首先创建并行Stream
?
答案 1 :(得分:3)
你问的是一个误导性的问题,首先你要问:
.parallelStream()
.forEachOrdered(...)
这将创建并行流,但元素将按顺序消耗。如果您添加map
这样的操作:
.map(...)
.parallelStream()
.forEachOrdered(...)
这将使map
非常有限(从并行处理的角度来看)操作,因为线程必须等待处理遭遇顺序中的所有其他元素(由forEachOrdered
消耗)。这涉及无国籍行动。
另一方面,如果你有有状态操作,如:
.parallelStream()
.map()
.sorted()
.// other operations
由于sorted
是有状态的,因此并行处理之前之前的无状态操作的好处将更大。之所以发生这种情况是因为sorted
必须从Stream中收集所有元素,并且线程不必“等待”(在forEachOrdered
)处理遇到顺序的元素。
对于第二个例子:
listOfIntegers.parallelStream()
.sequential()
.forEach(e -> System.out.print(e + " "))
你基本上是说并行打开然后关闭它。流是由终端操作驱动的,所以即使你这样做:
.map...
.filter...
.parallel()
.map...
.sequential
这意味着整个管道将按顺序执行,而不是某些部分将是并行的而另一部分是顺序的。你也依赖于forEach
保留秩序的事实,可能就在它发生的那一刻,但可能在以后的版本中,正如你说你不关心订单(使用forEach
首先,将有一个内部洗牌的元素。
答案 2 :(得分:2)
流管道可以顺序执行,也可以并行执行。此执行模式是流的属性。通过初始选择的顺序或并行执行来创建流。例如,Collection.stream()
创建一个顺序流,Collection.parallelStream()
创建一个并行流。可以通过BaseStream.sequential()
或BaseStream.parallel()
方法修改执行模式的选择。
所以没有必要使用:
listOfIntegers.parallelStream().sequential()
您只能使用:
listOfIntegers.stream()
如果要创建parallel stream
,则可以通过不同的线程处理流的元素。 forEach
和forEachOrdered
之间的区别在于forEach将允许以任何顺序处理并行流的任何元素,而forEachOrdered将始终按照它们的外观顺序处理并行流的元素。原始流。使用parallelStream()
时,forEachOrdered
是一个非常好的示例,说明如何利用多个内核并保持输出顺序。请注意,forEachOrdered以有序的方式强制迭代流的元素。但是,在forEachOrdered之前链接的任何操作仍然会并行发生,因为该流是并行流。
Oracle没有记录在管道中多次更改流执行模式时会发生什么。目前尚不清楚最后一次更改是否重要,或者调用parallel()
后调用的操作是否可以并行执行,调用sequential()
后调用的操作是否会按顺序执行。