Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Isn't it guaranteed that a parallel stream derived from a list will always behave like its sequential counterpart giving the same, predictable output?

The following code prints true for 100 times:

for(int i=0; i<100; i++) {
   String s2 = Arrays.asList("A", "E", "I", "O", "U").parallelStream().reduce("x", String::concat, String::concat);
   System.out.println("xAxExIxOxU".equals(s2));
}

Granted, 100 times is not a guarantee. But doesn't it seem though that even if the identity used here does not meet the requirement "...for all u, combiner.apply(identity, u) is equal to u" per the doc, we can still say that a parallel stream derived from a list or any other inherently ordered structure will behave just like a sequential stream in reduce() returning the same output?

like image 300
Treefish Zhang Avatar asked Jun 08 '19 21:06

Treefish Zhang


People also ask

What is true about parallel streams?

Parallel streams enable us to execute code in parallel on separate cores. The final result is the combination of each individual outcome.

Is parallel stream always efficient?

Similarly, don't use parallel if the stream is ordered and has much more elements than you want to process, e.g. This may run much longer because the parallel threads may work on plenty of number ranges instead of the crucial one 0-100, causing this to take very long time.

Which condition is to be satisfied to process a stream in parallel?

It is important to ensure that the result of the parallel stream is the same as is obtained through the sequential stream, so the parallel streams must be stateless, non-interfering, and associative.

What are the correct differences between parallel stream and sequential stream?

In the case of a sequential stream, the content of the list is printed in an ordered sequence. The output of the parallel stream, on the other hand, is unordered and the sequence changes every time the program is run. This signifies at least one thing: that invocation of the list.


1 Answers

The Javadoc for the Stream.reduce function with an identity argument says:

The identity value must be an identity for the accumulator function. This means that for all t, accumulator.apply(identity, t) is equal to t.

Which is clearly not the case here - "x".concat(anything) doesn't equal anything. The only valid identity value here is "".

If you had tested the premise of the title of your question - by seeing what a non-parallel operation returns - you'd see that the answer to your title is "no" - because a non-parallel stream returns "xAEIOU" for your reduce operation.

If you change the identity value from "x" to "", then the answer would be "yes, there is such a guarantee, as your reduce function is associative and the constraints on the identity value are also satisfied."

Even with your modified title, the answer is clear:

You are breaking the contract of the reduce function by providing, as the identity value, a value that is not an identity value for your reduce function. As such, since you are breaking the contract of the reduce methods, all guarantees are off.

It's easy to create a case where it doesn't hold; just make your list larger like Holger already pointed out:

List<String> list = new ArrayList<>();
for (int i = 0; i < 500; i++) {
    list.add("A");
}
String s2 = list.parallelStream().reduce("x", String::concat, String::concat);
System.out.println(s2);
if (s2.length() != list.size() * 2) {
    System.out.println("Bad s2 size");
}
like image 196
Erwin Bolwidt Avatar answered Oct 16 '22 23:10

Erwin Bolwidt