Iva*_*lin 25 java multithreading fork-join work-stealing forkjoinpool
我想Runnable通过一种方法将任务提交到ForkJoinPool:
forkJoinPool.submit(Runnable task)
Run Code Online (Sandbox Code Playgroud)
注意,我使用的是JDK 7.
在引擎盖下,它们被转换为ForkJoinTask对象.我知道当一个任务以递归方式分成较小的任务时,ForkJoinPool是有效的.
题:
如果没有递归,窃取工作仍然可以在ForkJoinPool中工作吗?
在这种情况下值得吗?
更新1: 任务很小,可能不平衡.即使对于严格相同的任务,诸如上下文切换,线程调度,停车,页面未命中等事情也会妨碍导致不平衡.
更新2: Doug Lea在Concurrency JSR-166兴趣小组中写道,给出了一个暗示:
当所有任务都是异步并提交到池而不是分叉时,这也极大地提高了吞吐量,这成为构造actor框架的合理方法,以及许多您可能使用ThreadPoolExecutor的普通服务.
我认为,当涉及到相当小的CPU绑定任务时,由于这种优化,ForkJoinPool是可行的方法.重点是这些任务已经很小,不需要递归分解.工作窃取工作,无论是大型还是小型任务 - 任务都可以被来自忙碌工人的Deque尾巴的另一个自由工作者抓住.
更新3: ForkJoinPool的可扩展性 - Akka乒乓球队的基准测试显示了很好的结果.
尽管如此,要更有效地应用ForkJoinPool需要进行性能调整.
Ale*_*lev 16
ForkJoinPool源代码有一个很好的部分称为"实现概述",阅读最终的真相.下面的解释是我对JDK 8u40的理解.
从第一天开始,ForkJoinPool每个工作线程都有一个工作队列(让我们称之为"工作队列").分叉的任务被推送到本地工作队列,准备好再次被工作者弹出并执行 - 换句话说,它看起来像工作线程角度的堆栈.当一个工作人员耗尽其工作队列时,它会绕过并试图从其他工作队列中窃取任务.那是"偷工作".
现在,在(IIRC)JDK 7u12之前,ForkJoinPool有一个全局提交队列.当工作线程用尽本地任务以及窃取任务时,他们到达那里并试图查看外部工作是否可用.在这种设计中,没有优势可以反对常规的,比如ThreadPoolExecutor支持ArrayBlockingQueue.
之后它发生了重大变化.在此提交队列被确定为严重的性能瓶颈之后,Doug Lea等人.条纹提交队列也是如此.事后看来,这是一个明显的想法:您可以重用大多数可用于工作队列的机制.您甚至可以按工作线程松散地分发这些提交队列.现在,外部提交进入其中一个提交队列.然后,没有工作的工作人员可以首先查看与特定工作者关联的提交队列,然后四处寻找其他人的提交队列.我们可以称之为是 "工作窃取"了.
我看到许多工作负载从中受益.ForkJoinPool很久以前就已经认识到这种特殊的设计优势,即使对于简单的非递归任务也是如此.并发兴趣@中的许多用户要求一个简单的工作窃取执行者,而不是所有的ForkJoinPoolarcanery.这是原因之一,为什么我们Executors.newWorkStealingPool()在JDK 8以后 - 目前委托ForkJoinPool,但开放提供更简单的实现.
| 归档时间: |
|
| 查看次数: |
2512 次 |
| 最近记录: |