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

Лучшие практики с Akka в Scala и сторонних библиотеках Java

Мне нужно использовать memcached Java API в моем коде Scala/Akka. Этот API дает вам как синхронные, так и асинхронные методы. Асинхронные возвращают java.util.concurrent.Future. Здесь был вопрос о работе с Java Futures в Scala здесь Как мне поместить java.util.concurrent.Future в будущее Akka?. Однако в моем случае у меня есть два варианта:

  • Использование синхронного API и кода блокировки в будущем и блокировки отметок:

    Future {
      blocking {
        cache.get(key) //synchronous blocking call
      } 
    }
    
  • Использование асинхронного Java API и опрос каждого n мс на Java Future, чтобы проверить, завершено ли будущее (как описано в одном из ответов выше в связанном вопросе выше).

Какой из них лучше? Я склоняюсь к первому варианту, потому что опрос может резко повлиять на время отклика. Не следует ли блокировать blocking { } блокировать весь пул?

4b9b3361

Ответ 1

Я всегда использую первый вариант. Но я делаю это несколько иначе. Я не использую функцию blocking. (На самом деле я еще не думал об этом.) Вместо этого я предоставляю специальный контекст выполнения в Будущее, которое обертывает синхронный блокирующий вызов. Так выглядит в основном так:

val ecForBlockingMemcachedStuff = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(100)) // whatever number you think is appropriate
// i create a separate ec for each blocking client/resource/api i use

Future {
    cache.get(key) //synchronous blocking call
}(ecForBlockingMemcachedStuff) // or mark the execution context implicit. I like to mention it explicitly.

Таким образом, все блокирующие вызовы будут использовать выделенный контекст выполнения (= Threadpool). Таким образом, он отделен от вашего основного контекста выполнения, ответственного за неблокирующий материал.

Этот подход также объясняется в интерактивном обучающем видеоролике

Ответ 2

Документация Akka содержит несколько предложений о том, как бороться с блокировкой вызовов:

В некоторых случаях неизбежно выполнять операции блокировки, т.е. нить в течение неопределенного времени, ожидая внешнего событие. Примерами являются устаревшие драйверы RDBMS или API-интерфейсы обмена сообщениями, и основная причина обычно заключается в том, что (сетевой) ввод-вывод происходит под обложки. Когда вы сталкиваетесь с этим, у вас может возникнуть соблазн просто обернуть блокируя вызов внутри Будущего и работая с ним вместо этого, но это стратегия слишком проста: вы, скорее всего, найдете узкие места или заканчивается память или потоки, когда приложение работает под повышенным нагрузки.

Неисчерпывающий список адекватных решений "блокировки" проблема "включает следующие предложения:

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

  • Сделайте блокирующий вызов в будущем, гарантируя верхнюю границу числа таких вызовов в любой момент времени (отправка неограниченного количество задач такого характера исчерпает вашу память или поток пределы).

  • Выполняйте блокирующий вызов в будущем, предоставляя пул потоков с верхним пределом количества потоков, который подходит для аппаратное обеспечение, на котором выполняется приложение.

  • Выделите один поток для управления набором блокирующих ресурсов (например, селектор NIO, управляющий несколькими каналами) и отправьте события, поскольку они происходят как сообщения субъекта.

Первая возможность особенно хорошо подходит для ресурсов, которые являются однопоточными по своей природе, такими как дескрипторы баз данных, которые традиционно может выполнять только один выдающийся запрос за раз и использовать внутренняя синхронизация для обеспечения этого. Общим примером является создание маршрутизатор для N участников, каждый из которых обертывает одно соединение с БД и обрабатывает запросы, отправленные на маршрутизатор. Затем должно быть настроено число N для максимальной пропускной способности, которая будет зависеть от того, какая СУБД развернуты на каком оборудовании.