Каково поведение scala.concurrent.ExecutionContext.Implicits.global?

Документация для scala.concurrent.ExecutionContext.Implicits.global в ExecutionContext:

Можно просто импортировать scala.concurrent.ExecutionContext.Implicits.global, чтобы получить неявный ExecutionContext. Этот глобальный контекст является разумным пул потоков по умолчанию

Что означает "разумный дефолт"?

Ответы

Ответ 1

По умолчанию

Это фиксированный размер ThreadPool, в котором столько потоков, сколько процессоры на машине. Разумный по умолчанию означает, что это хорошо для большинства вещей большую часть времени.

Что такое "хороший" пул потоков

Во-первых, важно понимать, что у вас есть столько потоков, сколько ядер на машине. Все остальные потоки - это так называемые потоки демонов, и все это связано с тем, что они умны с очередью и исполнением (на уровне языка/библиотеки).

CachedThreadPool: многие непродолжительные/дешевые задачи

Тип пулов потоков, которые вы создаете, значительно зависит от действий, которые они выполняют. Для большого количества коротких действий (например, запросов к базе данных) вы должны пойти с кэшированным пулом потоков.

Поскольку каждая отдельная задача относительно дешевая, но нереста новая нить дорого, вам лучше с CachedThreadPool.

FixedThreadPool: длительные/дорогостоящие задачи

В отличие от вышеизложенного, для очень дорогостоящих операций вы, вероятно, хотите ограничить количество потоков, выполняемых за один раз, по разным причинам: память, производительность и т.д.

ForkJoinPool: Divide et impera

Этот тип пула полезен, когда вам нужно выполнить очень большое вычисление, но вы можете разделить его на меньшие бит, которые могут вычислить отдельные работники.

Список можно продолжать и продолжать. Нижняя строка, Scala дает вам что-то среднее между всеми вышеперечисленными. В частности, Scala пытается создать ForkJoinPool и по умолчанию использует ThreadPoolExecutor, если первый сбой.

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
}

}

полный список.