Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the behavior of scala.concurrent.ExecutionContext.Implicits.global?

The documentation for scala.concurrent.ExecutionContext.Implicits.global on the ExecutionContext trait reads:

It is possible to simply import scala.concurrent.ExecutionContext.Implicits.global to obtain an implicit ExecutionContext. This global context is a reasonable default thread pool

What does it mean by "reasonable default"?

like image 995
Julio Faerman Avatar asked Mar 28 '14 02:03

Julio Faerman


People also ask

What is ExecutionContext in Scala?

An ExecutionContext can execute program logic asynchronously, typically but not necessarily on a thread pool. A general purpose ExecutionContext must be asynchronous in executing any Runnable that is passed into its execute -method.

What is Scala future?

Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.


1 Answers

Default

It's a fixed size ThreadPool, which has as many threads as the processors on the machine. A reasonable default means it's good for most things most of the time.

What a "good" thread pool is

First, it's important to understand you only have as many threads as the cores on the machine. All other threads are so called demon threads and it's all about being smart with queue-ing and executing.(at language/library level).

CachedThreadPool: Many short lived/cheap tasks

The type of thread pools you spawn vastly depend on the actions they are mean to perform. For a lot of short lived actions(say database queries), you would go a with a cached thread pool.

Because each individual task is relatively cheap but spawning a new thread is expensive, you are better off with a CachedThreadPool.

FixedThreadPool: Long running/expensive tasks

In contrast with the above, for very expensive operations, you probably want to limit the amount of threads running at one time, for various reasons: memory, performance etc.

ForkJoinPool: Divide et impera

This type of pool is useful when you need to perform a very large computation, but you can divide it into smaller bits individual workers can compute.

The list goes on and on. Bottom line, Scala gives you something in between all of the above. Specifically, Scala tries to create a ForkJoinPool and defaults to a ThreadPoolExecutor if the first fails.

try {
  new ForkJoinPool(
    desiredParallelism,
    threadFactory,
    uncaughtExceptionHandler,
    true) // Async all the way baby
} catch {
  case NonFatal(t) =>
    System.err.println("Failed to create ForkJoinPool for the default ExecutionContext, falling back to ThreadPoolExecutor")
    t.printStackTrace(System.err)
    val exec = new ThreadPoolExecutor(
      desiredParallelism,
      desiredParallelism,
      5L,
      TimeUnit.MINUTES,
      new LinkedBlockingQueue[Runnable],
      threadFactory
    )
    exec.allowCoreThreadTimeOut(true)
    exec
}

}

The full list here.

like image 157
flavian Avatar answered Oct 05 '22 23:10

flavian