ForkJoinPool在invokeAll/join期间停止

Dit*_*itz 6 java lock-free java.util.concurrent fork-join

我尝试使用ForkJoinPool 来并行化我的CPU密集型计算.我对ForkJoinPool的理解是,只要任何任务可以执行,它就会继续工作.不幸的是,我经常观察工作线程空闲/等待,因此并非所有CPU都保持忙碌状态.有时我甚至观察到额外的工作线程.

我没想到这一点,因为我严格尝试使用非阻塞任务.我的观察非常类似于ForkJoinPool似乎浪费了一个线程.在对ForkJoinPool进行了大量调试之后我猜了一下:

我使用invokeAll()在子任务列表上分配工作.在invokeAll()完成后执行第一个任务本身,它开始加入其他任务.这很好,直到下一个要连接的任务位于执行队列之上.不幸的是,我提交了异步的其他任务而没有加入它们.我期望ForkJoin框架首先继续执行这些任务,然后再转回加入任何剩余的任务.

但它似乎不是这样工作的.相反,工作线程停止调用wait()直到等待的任务准备好(可能是由其他工作线程执行).我没有验证这一点,但似乎是调用join()的一般缺陷.

ForkJoinPool提供了一个asyncMode,但这是一个全局参数,不能用于单个提交.但我喜欢看到我的异步分叉任务很快就会被执行.

那么,为什么ForkJoinTask.doJoin()不是简单地在其队列之上执行任何可用任务,直到它准备好(由自己执行或被其他人窃取)?

edh*_*ned 3

你对 join() 的看法是完全正确的。我两年前写了这篇文章,指出了 join() 的问题。

正如我所说,框架在完成之前的请求之前无法执行新提交的请求。每个 WorkThread 在当前请求完成之前无法窃取,这会导致 wait()。

您看到的附加线程是“延续线程”。由于 join() 最终会发出 wait(),因此需要这些线程,以便整个框架不会停止。

  • 该框架用于沿着平衡树的叶子向下行走。您没有做这个有限框架可以接受的事情。你得到的任何结果都没有现实依据。网上有很多关于如何正确使用这个框架的例子。 (2认同)