Akka docs指出默认调度程序是fork-join-executor
,因为它在大多数情况下都具有出色的性能。
我想知道为什么吗?
ForkJoinPool与其他类型的ExecutorService的不同之处在于,它采用了工作窃取:池中的所有线程都试图查找并执行提交给池和/或由其他活动任务创建的任务(最终,如果不存在)。这样,当大多数任务产生其他子任务时(大多数ForkJoinTasks也是如此),(1)高效处理;当许多小任务从外部客户端提交到池中时,(2)强>。尤其是在构造函数中将asyncMode设置为true时,ForkJoinPools也可能(3)适合与从未加入的事件样式任务一起使用。
起初,我想Akka不是案例(1)的示例,因为我无法弄清楚Akka如何分叉任务,我的意思是,在许多任务中可以分叉的任务是什么?
我认为每条消息都是独立的任务,这就是为什么我认为Akka与情况(2)类似的原因,在该情况下,消息是许多小任务(通过!和?)提交给ForkJoinPool
。
尽管与akka并不严格相关,但下一个问题将是,为什么仍然可以使用不使用fork and join(允许进行偷窃的主要功能ForkJoinPool
)的用例。受益于ForkJoinPool?
来自Scalability of Fork Join Pool
我们注意到上下文切换的数量异常,每秒超过70000。
那一定是问题所在,但是是什么原因造成的呢? Viktor提出了一个合理的猜测,即它必须是线程池执行程序的任务队列,因为它是共享的,并且在发生争用时,LinkedBlockingQueue中的锁有可能生成上下文切换。>
但是,如果确实Akka不使用ForkJoinTasks
,则外部客户端提交的所有任务都将在共享队列中排队,因此争用应该与ThreadPoolExecutor
中的争用相同。
所以,我的问题是:
ForkJoinTasks
(案例(1))还是与案例(2)相关?ForkJoinPool
有好处?正确的答案是johanandren的答案,但是我想添加一些要点。
现在,在(IIRC)JDK 7u12之前,ForkJoinPool具有单个全局提交队列。当工作线程用尽本地任务以及要窃取的任务时,他们到达那里并尝试查看是否有外部工作可用。在这种设计中,与由ArrayBlockingQueue支持的常规ThreadPoolExecutor相比,没有任何优势。 [...]
现在,外部提交进入提交队列之一。然后,没有工作需要上班的工作人员可以先查看与特定工作人员相关联的提交队列,然后四处逛逛以查看其他人的提交队列。人们也可以称其为“偷工作”。
因此,这在不使用fork联接的情况下实现了工作窃取。以Doug Lea says
当许多客户端提交许多任务时,吞吐量显着提高。 (我测得的speedupson微基准测试最高可达60倍)。想法是像对待工人一样对待外部提交者-使用随机排队和窃取。 (这需要进行大量的内部重构以分离工作队列和工作程序。)当所有任务都异步并提交到池中而不是分叉时,这也极大地提高了吞吐量,这成为构造actor框架以及许多您可能会使用的纯服务的合理方法ThreadPoolExecutor用于。
FJP的4%确实不多。与FJP仍然需要权衡 您需要注意以下几点: FJP使线程保持旋转一段时间。 能够更快地处理准时到达的工作。这样可以确保良好的延迟 在很多情况下。但是,特别是如果您的池超额配置, 权衡是一点点的等待时间,几乎是闲置时的更多功耗 情况。
答案 0 :(得分:3)
Akka的FJP与asyncMode = true
运行,因此第一个问题是-外部客户端提交短/小的异步工作负载。每个提交的工作负载要么派遣一个actor处理其收件箱中的一条或几条消息,但也用于执行Scala Future
操作。
当非ForkJoinTask
计划在FJP上运行时,它会适应FJP并像ForkJoinTask
一样排队。没有一个单一的提交将任务排入队列(可能是早期版本的JDK7),有很多避免争用的方法,并且空闲线程可以从其他队列(窃取)中挑选(窃取)任务空的。
请注意,默认情况下,当前我们在Java 8 FJP的分支版本上运行,因为Java 9 FJP的吞吐量显着下降(它进行了很多更改)。如果您有兴趣,这里是issue #21910 discussing that。另外,如果您想测试不同池的基准,则可以在此处找到一些*Pool
个基准:https://github.com/akka/akka/tree/master/akka-bench-jmh/src/main/scala/akka/actor
答案 1 :(得分:1)
http://letitcrash.com/post/17607272336/scalability-of-fork-join-pool
叉连接池的可伸缩性
由于Doug Lea开发了新的fork join执行程序,因此Akka 2.0消息传递吞吐量在多核硬件上的扩展方式比以前的版本更好。一个微型基准测试表明吞吐量提高了1100%!
...
http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008987.html
...
要点:
这些改进也导致对 提交可能阻塞的任务。一个附加的参数 ForkJoinTask文档提供了一些指导 (基本上:如果它们很小(即使数量很多),我们也会喜欢) 并且没有依赖性)。
...