我尝试使用ForkJoinPool 来并行化我的 CPU 密集型计算。我对 ForkJoinPool 的理解是,只要可以执行任何任务,它就会继续工作。不幸的是,我经常观察到工作线程空闲/等待,因此并非所有 CPU 都保持忙碌。有时我什至观察到额外的工作线程。
我没想到会这样,因为我严格尝试使用非阻塞任务。我的观察与 ForkJoinPool 的观察非常相似,似乎浪费了一个线程。在对 ForkJoinPool 进行大量调试后,我有一个猜测:
我使用 invokeAll() 在子任务列表上分配工作。在 invokeAll() 完成执行第一个任务本身之后,它开始加入其他任务。这工作正常,直到下一个要加入的任务位于执行队列的顶部。不幸的是,我在没有加入的情况下异步提交了其他任务。我希望 ForkJoin 框架首先继续执行这些任务,然后再返回加入任何剩余的任务。
但它似乎不是这样工作的。相反,工作线程停止调用 wait(),直到等待的任务准备好(可能由另一个工作线程执行)。我没有验证这一点,但这似乎是调用 join() 的一般缺陷。
ForkJoinPool 提供了一个asyncMode,但这是一个全局参数,不能用于单个提交。但我喜欢看到我的异步分叉任务很快就会被执行。
那么,为什么 ForkJoinTask.doJoin() 不简单地在其队列顶部执行任何可用任务,直到它准备好(自己执行或被其他人窃取)?