Подтвердить что ты не робот

Использовать контексты исполнения vs scala global

Как контекст выполнения из

import scala.concurrent.ExecutionContext.Implicits.global

отличаются от контекстов исполнения воспроизведения:

import play.core.Execution.Implicits.{internalContext, defaultContext}
4b9b3361

Ответ 1

Они очень разные.

В Play 2.3.x и предыдущем, play.core.Execution.Implicits.internalContext является ForkJoinPool с фиксированными ограничениями на размер, которые используются внутри игры. Вы никогда не должны использовать его для своего кода приложения. Из документов:

Воспроизведение внутреннего пула потоков - это используется внутри игры. Никакой код приложения никогда не должен выполняться потоком в этом пуле потоков, и в этом пуле потоков никогда не должно быть блокировки. Его размер можно настроить, установив параметр internal-threadpool-size в application.conf, и по умолчанию используется количество доступных процессоров.

Вместо этого вы должны использовать play.api.libs.concurrent.Execution.Implicits.defaultContext, который использует ActorSystem.

В 2.4.x оба они используют один и тот же ActorSystem. Это означает, что Akka будет распространять работу среди своего пула потоков, но таким образом, который невидим для вас (кроме конфигурации). Несколько актеров Akka могут делиться одним и тем же потоком.

scala.concurrent.ExecutionContext.Implicits.global является ExecutionContext, определенным в стандартной библиотеке Scala. Это специальный ForkJoinPool, который использует метод blocking для обработки потенциально блокирующего кода, чтобы порождать новые потоки в пуле. Вы действительно не должны использовать это в приложении Play, так как Play не будет контролировать его. Он также имеет потенциал для создания множества потоков и использования тонны памяти, если вы не будете осторожны.

Я написал больше о scala.concurrent.ExecutionContext.Implicits.global в этом ответе.

Ответ 2

Они одинаковы и указывают на диспетчера по умолчанию базовой действующей системы в вашем Play или Akka или комбинированное приложение.

Контекст воспроизведения по умолчанию

play.api.libs.concurrent.Execution.Implicits.defaultContext

Воспроизвести внутренний контекст

play.core.Execution.Implicits.internalContext

Гик-код EC Injected

class ClassA @Inject()(config: Configuration)
                           (implicit ec: ExecutionContext) {
...
}

Но это другое:

scala.concurrent.ExecutionContext.Implicits.global

Также драйверы DB, например. если вы используете пятно, может возникнуть свой собственный контекст выполнения. Во всяком случае,


Рекомендации:

  • Не используйте scala.concurrent.ExecutionContext.Implicits.global, когда вы находитесь в игре или в каркасе akka, таким образом вы можете использовать больше потоков, чем оптимально во время высокой нагрузки, поэтому производительность может уменьшиться.
  • Не бойтесь! используйте диспетчер по умолчанию столько, сколько вы хотите повсюду, если вы не выполняете какую-либо задачу блокировки, например, при прослушивании в сетевом соединении, или явно читаете из db, что делает вас "текущей тидрой", ожидающей результата.
  • Начните с исполнителя по умолчанию, и если вы обнаружили, что Play/Akka плохо реагирует во время высокой нагрузки, переключитесь на новый пул потоков для трудоемких задач вычисления.
    • Вычислительные задачи, которые занимают много времени, обычно не рассматриваются как блокирование. Например, перемещение дерева автозаполнения в памяти. Но вы можете считать их блокирующими, если хотите, чтобы ваши управляющие структуры оставались работоспособными, когда у вас есть время, затрачиваемое на выполнение вычислительной задачи.
    • Плохая вещь, которая может случиться, когда вы считаете, что задачи вычисления не блокируются, заключается в том, что диспетчер сообщений игры и Akka будет приостановлен, когда все потоки будут вычисляться с большой нагрузкой. Преимуществом отдельного диспетчера является то, что процессор очереди не голодает. The Cons с отдельным диспетчером состоит в том, что вы можете выделить больше потоков, которые будут оптимальными, и ваша общая производительность будет уменьшена.
    • Разница заключается в серверах с высокой нагрузкой, не беспокоитесь о небольших проектах, используйте по умолчанию
  • Используйте scala.concurrent.ExecutionContext.Implicits.global, если в вашем приложении нет другого исполнителя. Не беспокойтесь, это безопасно тогда.
  • После создания фьючерсов используйте пул по умолчанию, это самый безопасный способ, если вы не уверены, что будущее блокирует. Затем используйте отдельный пул или используйте блокировку {}, если это возможно.
  • Создайте отдельный пул потоков один раз
    • Вы Await для будущего
    • Вы вызываете Thread.sleep
    • Вы читаете вызов stream/socket/http
    • Вручную запрашивать db с помощью драйвера блокировки (обычно это безопасно)
    • Запланировать задачу, которая будет запущена за 10 секунд
    • Запланировать задачу, которая будет выполняться каждую секунду
  • Для операций отображения/восстановления в будущем используйте исполнитель по умолчанию, обычно это безопасно
  • Обработка исключений безопасна с диспетчером по умолчанию
  • Всегда используйте диспетчеров Akka с вами в Play или Akka, имеет хороший способ определить нового диспетчера в application.conf