Dispatcher解析
Dispathcer负责调度并行任务,负责将工作分配给Actor,还可以分配资源用于处理Future的回调,可以理解为Dispatcher和Executor为线程池中线程的调度器。
跟线程池一样,不自己创建Dispatcher时使用的是默认Dispathcer,如果任务中有些耗时任务,容易将默认线程池打满,影响其他任务的调度。
Excutor
Dispatcher基于Excutor,介绍Dispatcher前先介绍下Excutor
- Excutor分为两种: ForkJoinPool、ThreadPool
- ThreadPool Excutor: 有一个工作队列,队列中包含了分配给各队列的工作,线程空闲时就从队列中认领工作,允许线程重用,减少线程分配和销毁的开销
- ForkJoinPool Excutor: 使用一种分治算法,递归地将任务分隔成更小的子任务,然后把子任务分配给不同的线程运行,最后将运行结果组合起来
- ForkJoinPoll几乎总比ThreadPool效率更高,是我们默认选择
Dispatcher分类
- Dispatcher: 默认的Dispatcher类型,使用定义的Excutor在Actor中处理消息,大多情况下可以提供最好的性能
- PinnedDispatcher: 给每个Actor分配独有的线程,为每个Actor都创建一个ThreadPool Excutor,每个Excutor中包含一个线程,可以在单个Actor中处理很多重要工作时候使用这种Dispatcher, 否则不推荐使用
- CallingThreadDispatcher: 不创建Excutor,在发起调用的线程上执行工作,主要用于测试或者是调试
- BalancingDispatcher: Pool中的所有Acotr都共享同一个邮箱,并且为POOL中的每个Actor都创建一个县城,只要有Acotr处于空闲状态都会从共享邮箱中领任务,现在已经不推荐直接使用此类Dispatcher了,应该使用前面Router章节中使用到的BalancingPool Router
Dispatcher使用
上面是Dispather的理论部分,下面将着重介绍Dispatcher如何使用。
创建Dispatcher
- 在 application.conf文件中定义一个Dispatcher,如下所示
- 参数解析
- type: Dispatcher的类型,选择符合场景的Dispatcher,这里使用的是默认类型Dispatcher
- executor: 定义Excutor类型,上面也介绍过两种Excutor
- parallelism-min: 单核最少线程数,Excutor中最少线程数=parallelism-min*parallelism-factor
- parallelism-factor: 此项最好配置成机器的CPU核数
- parallelism-max: 单核最多线程数,Excutor中最多线程数=parallelism-max*parallelism-factor
- throughput: 跳到另一个Acotr之前每个Actor最多处理消息数量,这个参数为了防止单个Acotr一直占用线程,设置此Acotr最多执行多少消息就要被调度
detect-dispatcher { # Dispatcher is the name of the event-based dispatcher type = Dispatcher # What kind of ExecutionService to use executor = "fork-join-executor" # Configuration for the fork join pool fork-join-executor { # Min number of threads to cap factor-based parallelism number to parallelism-min = 2 # Parallelism (threads) ... ceil(available processors * factor) parallelism-factor = 24.0 # Max number of threads to cap factor-based parallelism number to parallelism-max = 1000 } # Throughput defines the maximum number of messages to be # processed per actor before the thread jumps to the next actor. # Set to 1 for as fair as possible. throughput = 1000 }
- 使用自定义的Dispatcher,这样创建的DetectRouterActor就都是用自己定义的Dispatcher了
ActorSystem actorSystem = ActorSystem.create("detectTask"); ActorRef routerActorRef = actorSystem.actorOf( Props.create(DetectRouterActor.class).withDispatcher("detect-dispatcher");
- 假如想在使用dispatcher基础上使用Router和指定邮箱,只要这样创建就好了
ActorSystem actorSystem = ActorSystem.create("detectTask"); ActorRef routerActorRef = actorSystem.actorOf( Props.create(DetectRouterActor.class).withMailbox("akka.actor.routermailbox") .withDispatcher("detect-dispatcher").withRouter(new SmallestMailboxPool(15000)), "detectRouterActor");