官术网_书友最值得收藏!

A word on dispatchers in Akka

Throughout some of the previous sections, I've mentioned the dispatcher within Akka. This is an extremely important component within Akka's actor system. In Akka's docs, they refer to it as the engine that makes the actor system tick, which I think is a very apt description. Since this component is so important, I want to touch on what it does a bit and also describe the different types and why you might use them.

Dispatchers and executors

The dispatcher in your actor system is responsible for assigning a thread to an actor instance so that it can do work. When an actor instance has no messages to process, it just sits there idle, not taking up any threads. This is why it's okay to have so many actor instances within your system at once (as long as they are not all trying to do work all the time). They don't take any resources, aside from a small amount of heap memory, unless they are processing a message.

Akka is an event-driven system. Work is only done in response to an event being received. The event in this case is a message being received in the mailbox of an actor instance. When the dispatcher sees this, a thread is allocated, and the work of processing that message can begin. When there are no messages to process, the threads sit idle until something happens and there is work to be done.

So where does the dispatcher get those threads from? A dispatcher will always be paired up with an executor, which will define what kind of thread pool model is used to support the actors. In fact, MessageDispatcher in Akka inherits from ExecutionContext. This means that any place where you need ExecutionContext, like when using Futures in your actors, you can use that actor's dispatcher to satisfy that requirement. You may have noticed me doing this in a few places in the various code samples in this chapter.

Dispatcher types in Akka

Akka offers a total of three different dispatcher types, with an additional fourth one that is only really used for testing. Each of these has its own purpose and sweet spot within Akka. I'll try and describe that briefly here. If you want a more detailed explanation, check out the Akka docs on dispatchers.

Dispatcher

This is the default type for any actor instance where an explicit dispatcher is not specified. It is completely all purpose, in that, it can be used as the main dispatcher for the actor system as well as firewalling (or bulkheading) off actors that may block or cause problems for the main dispatcher. It can be used with any mailbox type and works with both a Fork/Join pool executor or a basic thread pool executor for its thread handling.

PinnedDispatcher

This dispatcher is unique, in that, each and every actor instance created under it will get assigned its own single thread for executing it. This is a specialist dispatcher that can be used to firewall off (protect against) actors that block as part of their execution. It can also be used for actors whose execution might have a negative effect on the main dispatcher, perhaps hogging threads from that dispatcher.

BalancingDispatcher

This dispatcher is unique, in that, every actor instance created under it will share a single mailbox. This is to support redistribution of work from instances that are busy to instances that are idle. If you find that you have a use case where you have a pool of the same actors and they get a lot of work and each piece may take a variable amount of time, this may be a good dispatcher to try. If this dispatcher is able to better redistribute work in that situation, then you may find that your work will be done more quickly.

CallingThreadDispatcher

This is the dispatcher that should only be used in testing situations. Using this dispatcher (which automatically happens if you wrap an actor with TestActorRef) will ensure that all execution within your test will be synchronous instead of the default asynchronous behavior.

This makes testing your actor code a lot easier as requests to your actors (via tell) will return control to the calling thread (hence, the name) only after all of the code in receive has executed. Having this guarantee makes performing test assertions more consistent.

Configuring a dispatcher for your actors

When you need to use a dispatcher for an actor other than the default one, then you first have to configure that dispatcher. Here, I'm going to configure a new thread pool-based dispatcher to section off some blocking I/O work that a particular actor has to do:

thread-pool-dispatcher { 
  type = Dispatcher 
  executor = "thread-pool-executor" 
  thread-pool-executor { 
    core-pool-size-min = 2 
    core-pool-size-factor = 2.0 
    core-pool-size-max = 10 
  } 
  throughput = 100 
} 

Here, I have configured that new dispatcher, with a type of Dispatcher, which is the normal event-based dispatcher. It's set up to use a thread pool as its executor, with the min and max size of the pool set to 2 and 10 respectively. The throughput setting here means that the dispatcher will process up to 100 messages on any given actor instance before context switching the thread over to another actor instance.

Once you have that config defined, then you can apply it to an actor instance. The first possible way to do this is via the deployment config for that actor instance, which is shown below:

akka.actor.deployment{ 
  /foo-actor{ 
    dispatcher = thread-pool-dispatcher 
  } 
} 

With config like that in place, I can then simply spin up an actor instance like this and get it to use my custom dispatcher:

Val fooRef = system.actorOf(Props[FooActor], "foo-actor") 

If you don't want to go the route of using deployment config to set the dispatcher for your actor instance, then you can manually set it at time of creation via the Props for that actor, like so:

val fooRef = 
  context.actorOf( 
    Props[FooActor]. 
      withDispatcher("thread-pool-dispatcher"), "myactor1" 
  ) 

These two approaches are semantically the same, so just choose which of the two suits your style better.

One thing to note when specifying dispatchers that way; the config path that you are referencing to the mailbox config section must be fully qualified within the context of your complete config tree. If you are nesting that custom dispatcher config section under some other parent sections, then you must fully qualify the path to the dispatcher config when referencing it or it will not be applied to your actor instance.

主站蜘蛛池模板: 剑阁县| 泌阳县| 资溪县| 苏尼特左旗| 平和县| 衡南县| 日照市| 平潭县| 肇东市| 长海县| 河西区| 永寿县| 邓州市| 大庆市| 临夏市| 南澳县| 鹿邑县| 营口市| 志丹县| 娱乐| 从江县| 孟州市| 林口县| 彭州市| 阳曲县| 边坝县| 呼和浩特市| 余干县| 凭祥市| 馆陶县| 苏州市| 罗山县| 遂川县| 岳阳县| 谷城县| 中山市| 唐河县| 连江县| 辽源市| 连江县| 潍坊市|