user9405697
user9405697

Reputation:

Which ExecutionContext to choose for Future in Akka applications?

When execute a Future, we need an execution context.

Afaik, we can use following solution:

1.

import scala.concurrent.ExecutionContext.Implicits.global

2.

import context.dispatcher

or

implicit val ec = context.system.dispatcher

3.

implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10))

My question is: What's the difference between them? What's the suggest way?

E.g. Solution2 will reuse the dispatcher of actor, while solution1 will use separate fixed pool, the thread number is same as cpu core. I just know some snippet of the difference, anyone could explain more? Thanks!

Upvotes: 12

Views: 4871

Answers (2)

Jeffrey Chung
Jeffrey Chung

Reputation: 19517

Apparently you're using Futures within an actor, since you mention context.dispatcher and context.system.dispatcher. Note that these two options are not necessarily the same (but they typically are the same):

  • context.system.dispatcher is the default dispatcher.
  • context.dispatcher is the dispatcher for a particular actor, which is the same as the default dispatcher unless you set up a custom dispatcher for the actor programmatically or via the configuration.

As for which ExecutionContext to use with a Future inside an actor, the documentation advises the following:

If the nature of the Future calls invoked by the actor matches or is compatible with the activities of that actor (e.g. all CPU bound and no latency requirements), then it may be easiest to reuse the dispatcher for running the Futures by importing context.dispatcher.

However, if the Future wraps a blocking operation, then using context.dispatcher (which, as mentioned, is usually the default dispatcher) could cause the other actors sharing the same dispatcher to starve for threads. In this scenario, use a dedicated dispatcher, which in your actor would like something like this:

implicit val executionContext: ExecutionContext =
  context.system.dispatchers.lookup("my-blocking-dispatcher")

my-blocking-dispatcher would be defined in application.conf. For example:

my-blocking-dispatcher {
  type = Dispatcher
  executor = "thread-pool-executor"
  thread-pool-executor {
    fixed-pool-size = 10
  }
  throughput = 1
}

Also note that defining a custom dispatcher in the configuration and letting the actor system instantiate it is the preferred approach to setting up a thread pool in Akka. That is, use the above approach instead of using

implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10))

In short, when using Futures within actors, consider using context.dispatcher in general. However, if you're dealing with blocking or long-running operations with the Futures, then use a dedicated dispatcher to bulkhead or isolate those operations from impacting the rest of the system.

Upvotes: 14

Evgeny
Evgeny

Reputation: 1770

Future itself is description of functionality. To be executed, it requires Thread which is taken from execution context.

As soon as you mentioned context.dispatcher, than you use akka. Each actor while executed, also executed by thread in specific execution context. When you run Future using context.dispatcher, you run this Future in same thread pool as used by current actor. In other words, you share available (limited!) amount of threads for additional functionality. Depending on how long are execution of your futures, actors could start to wait for available threads if all threads are occupied by not completed futures.

In akka you can define thread pools (dispatchers) in configuration file. And deploy actors accordingly. For futures, you can use either dispatcher of actor starting this future, of specific thread pool (I would recommend in this case not to use global, but define specific akka dispatcher for futures). Depends on your application (both cases could be fine)

About akka dispatchers see here

Upvotes: -2

Related Questions