派发器
Akka MessageDispatcher是维持Akka Actor“运作”的部分,可以说它是整个机器的引擎。所有的MessageDispatcher实现也同时是一个ExecutionContext,这意味着它们可以用来执行任何代码,例如Future。
默认的派发器
在没有为Actor作任何配置的情况下,每个ActorSystem将有一个默认的派发器。默认派发器是可配置的,默认情况下是具有指定default-executor的Dispatcher。如果用ExecutionContext来创建ActorSystem,在ActorSystem中,此ExecutionContext将作为所有派发器的默认执行器。如果没有指定ExecutionContext,将后退到akka.actor.default-dispatcher.default-executor.fallback的executor。缺省情况下的”fork-join-executor”,在大多数情况下拥有非常好的性能。
查找派发器
派发器实现ExecutionContext接口,因此可以用来运行Future调用等等。
//this is scala.concurrent.ExecutionContext //for use with Futures, Scheduler, etc. final ExecutionContext ex = system.dispatchers().lookup("my-dispatcher"); |
为角色设置派发器
在你想为Actor配置一个不同派发器而不是默认情况下,你需要做两件事,第一件事是配置派发器:
my-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 = 2.0
# Max number of threads to cap factor-based parallelism number to
parallelism-max = 10
}
# 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 = 100
}
这里是另一个是使用“thread-pool-executor”的例子:
my-thread-pool-dispatcher {
# Dispatcher is the name of the event-based dispatcher
type = Dispatcher
# What kind of ExecutionService to use
executor = "thread-pool-executor"
# Configuration for the thread pool
thread-pool-executor {
# minimum number of threads to cap factor-based core number to
core-pool-size-min = 2
# No of core threads ... ceil(available processors * factor)
core-pool-size-factor = 2.0
# maximum number of threads to cap factor-based number to
core-pool-size-max = 10
}
# 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 = 100
}
更多细节选项,请参见配置的默认派发器章节。
然后你就可以像平常一样创建角色和在部署配置中定义派发器。
ActorRef myActor =
system.actorOf(Props.create(MyUntypedActor.class),
"myactor");
akka.actor.deployment {
/myactor {
dispatcher = my-dispatcher
}
}
一种代替部署配置方法是在代码里面定义派发器。如果在部署配置里面定义派发器配置,则该值代替编码提供的参数。
ActorRef myActor =
system.actorOf(Props.create(MyUntypedActor.class).withDispatcher("my-dispatcher"),
"myactor3");
注意:你在withDispatcher中指定的派发器和在部署配置中的dispatcher属性其实是配置中的一个路径。所以在这个例子中,它位于配置的顶层,但你可以把它放在下面的层次,用.来代表子层次,象这样:“foo.bar.my-dispatcher”。
派发器的类型
总共有4种类型的消息派发器:
- Dispatcher
- 这是个基于事件派发器,该派发器绑定一组角色到一个线程池中。如果没有一个明确定义,这将是一个默认派发器使用。
- 可共享性: 无限制
- 邮箱: 任何,为每一个Actor创建一个
- 使用场景: 缺省派发器,Bulkheading
- 底层使用: java.util.concurrent.ExecutorService
用“executor”、“fork-join-executor”、“thread-pool-executor”或 akka.dispatcher.ExecutorServiceConfigurator的全限定名(FQCN)指定
- PinnedDispatcher
- 该派发器致力于为每一个使用它的角色提供一个唯一的线程,例如:每一个角色将有自己的仅包含一个线程的线程池。
- 可共享性: 无
- 邮箱: 任何,为每个Actor创建一个
- 使用场景: Bulkheading
- 底层使用: 任何akka.dispatch.ThreadPoolExecutorConfigurator
缺省为一个 “thread-pool-executor”
- CallingThreadDispatcher
- 该派发器仅在当前线程上运行调用。此派发器不会创建任何新的线程,但可以使用来自不同的线程同时为相同的角色。请见 CallingThreadDispatcher for细节和限制
- 可共享性: 无限制
- 邮箱: 任何,每Actor每线程创建一个(需要时)
- 使用场景: 测试
- 底层使用: 调用的线程 (duh)
更多派发器配置例子
配置PinnedDispatcher:
my-pinned-dispatcher {
executor = "thread-pool-executor"
type = PinnedDispatcher
}
然后使用它:
ActorRef myActor = system.actorOf(Props.create(MyUntypedActor.class)
.withDispatcher("my-pinned-dispatcher"));
注意:thread-pool-executor配置按照上面my-thread-pool-dispatcher例子是不适用的。这是因为当使用PinnedDispatcher时候,每一个角色将有自己的线程池,线程池中只有一个线程。
注意:随着时间推移这将不保证一直使用相同线程,由于核心池超时用于PinnedDispatcher在闲置角色情况下,降低资源使用。为了一直使用相同的线程,你需要在PinnedDispatcher配置中添加thread-pool-executor.allow-core-timeout=off。