[concurrency-interest] ForkJoinPool not designed for nested Java 8 streams.parallel().forEach( ... )

Christian Fries email at christian-fries.de
Tue May 6 11:38:58 EDT 2014

Hi Paul.
Hi All.

Thank you for the suggestion. However - I do not need any manage blocker to perfectly solve that performance issue. A simple workaround is the following:

Add the method
	private void wrapInThread(Runnable runnable) {
		Thread t = new Thread(runnable, "Wrapper Thread");
		try {
		} catch (InterruptedException e) { }
(which obviously does not create any additional parallelism) and then wrap the inner loop in that „Wrapper Thread“ via
	wrapInThread( () ->
		IntStream.range(0,numberOfTasksInInnerLoop).parallel().forEach(j -> {
(by which all inner loop tasks are still submitted to the common F/J pool). With this you get full performance (32 sec).

Why is this fixing the problem? I assume the explanation goes s.th. like this:

When you use a nested loop, it may be that the inner loop is started on a ForkJoinWorkerThread (and not on a non-worker thread - as a non-nested loop would do).
Now, the FJP distinguishes a worker thread from a non-worker thread via the line
  ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
i.e. it checks its type.
Now, since the inner loop is started on a ForkJoinWorkerThread (one of the outer, but that info is not present), he considers this thread as one of its worker threads and calls awaitJoin - actually joining with the outer loops work queue.
Starting the inner loop on a wrapper thread, the type of Thread.currentThread() will just be Thread and not ForkJoinWorkerThread, hence, we call an externalAwaitDone() instead.
So just wrap every parallel().forEach() in its own Thread (immediately joining) and nested loop work fine.

I am not completely sure that every detail is as described, but I assume that the problem is somewhat like that.


PS: Sorry, I am new to this list. Is this the right list to discuss such low level code issues? The code I am referring to is at: http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/6be37bafb11a/src/share/classes/java/util/concurrent/ForkJoinTask.java#l401

Am 06.05.2014 um 16:44 schrieb Paul Sandoz <paul.sandoz at oracle.com>:

> Hi,
> On May 6, 2014, at 3:01 PM, Christian Fries <email at christian-fries.de> wrote:
>> Hi Paul.
>> Oh. I expected that it would be countered that „Thread.sleep()“ is not be a legitimate test case… ;-)
> :-) I think what you have now with CPU burning is more relevant and also different from where you started. Have you tried writing a jmh benchmark instead? i would recommend doing so if you want to further explore the performance characteristics.
>> I have update my demo and now I use a stupid for-loop summing up some cosine to burn real CPU time. The result is
>> Nested stream forEach: outer parallel, inner sequential:	34 sec
>> Nested stream forEach: outer parallel, inner parallel:		63 sec
> That is not too surprising, to me at least, from my previous experience and esp. what Doug said about nested parallelism.
>> In the first case my 8-core CPU ist working at 800% all the time. In the second case you can clearly see that its almost idle at certain times.
>> You find my updated test case here:
>> http://svn.finmath.net/finmath%20experiments/trunk/src/net/finmath/experiments/concurrency/NestedParallelForEachTest.java
>> If you like to not use Thread.sleep() set isCPUTimeBurned to true - you might need to calibrate that count used in the loop.
> FWIW you can do: 
>                     ForkJoinPool.managedBlock(blocker(() -> {
>                         // Inner loop as parallel: worst case (sequential) it takes 10 * numberOfTasksInInnerLoop millis
>                         IntStream.range(0,numberOfTasksInInnerLoop).parallel().forEach(j -> {
>                             burnTime(10);
>                         });
>                     }));
> which enables work to balance out a bit more, but could be regarded as somewhat of an abuse.
> Paul.
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20140506/aafcec80/attachment-0001.html>

More information about the Concurrency-interest mailing list