Reputation:
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
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
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