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

Какой эффект имеет использование Action.async, поскольку Play использует Netty, который не блокирует

Так как Netty является неблокирующим сервером, какое действие меняет действие на использование .async?

def index = Action { ... }

против

def index = Action.async { ... }

Я понимаю, что с .async вы получите Future[SimpleResult]. Но так как Netty не блокирует, будет ли вообще играть что-то подобное под обложками?

Какое влияние это будет на пропускную способность/масштабируемость? Не трудно ли ответить на вопрос, где это зависит от других факторов?

Причина, по которой я спрашиваю, у меня есть собственный пользовательский Action, и я хотел reset тайм-аут cookie для каждого запроса на страницу, поэтому я делаю это, что является вызовом async:

object MyAction extends ActionBuilder[abc123] {
  def invokeBlock[A](request: Request[A], block: (abc123[A]) => Future[SimpleResult]) = {
    ...
    val result: Future[SimpleResult] = block(new abc123(..., result))
    result.map(_.withCookies(...))
  }
}

Убрать из вышеприведенного фрагмента я использую Future[SimpleResult], похоже ли это на вызов Action.async, но это внутри самого моего действия?

Я хочу понять, какое влияние это окажет на мой дизайн приложения. Кажется, что только для возможности установить мой файл cookie на основе запроса я изменил с блокировки на неблокирующую. Но я смущен, так как Netty не блокирует, может быть, я на самом деле ничего не изменил, поскольку это было уже асинхронно?

Или я просто создал другой асинхронный вызов, встроенный в другой?

Надеясь, что кто-то сможет прояснить это с некоторыми деталями и как или каким эффектом это будет иметь производительность/пропускная способность.

4b9b3361

Ответ 1

def index = Action { ... } неблокирует, вы правы.

Цель Action.async состоит в том, чтобы упростить работу с Futures в ваших действиях.

Например:

def index = Action.async {
  val allOptionsFuture: Future[List[UserOption]] = optionService.findAll()
  allOptionFuture map {
    options =>
      Ok(views.html.main(options))
  }
}

Здесь моя служба возвращает Future, и, чтобы избежать обработки результата, я просто сопоставляю его с Future[SimpleResult] и Action.async, который заботится обо всех остальных.

Если моя служба возвращала List[UserOption] напрямую, я мог просто использовать Action.apply, но под капотом все равно будет неблокировать.

Если вы посмотрите на исходный код Action, вы даже увидите, что apply в конечном итоге вызывает async: https://github.com/playframework/playframework/blob/2.3.x/framework/src/play/src/main/scala/play/api/mvc/Action.scala#L432

Ответ 2

Мне довелось встретить этот вопрос, мне нравится ответ от @vptheron, и я также хочу поделиться чем-то, что я прочитал из книги " Reactive Web Applications", что, я думаю, также Великий.

Конструктор Action.async рассчитывает получить функцию типа Request => Future[Result]. Действия, объявленные таким образом, мало чем отличаются от обычных вызовов Action { request => ... }, единственное отличие состоит в том, что Play знает, что действия Action.async уже асинхронны, поэтому они не обертывают их содержимое в будущий блок.

Правильно. По умолчанию Play будет планировать любое действие, которое будет выполняться асинхронно с его пулом веб-рабочих по умолчанию, завершая выполнение в будущем. Единственное различие между Action и Action.async заключается в том, что во втором случае заботились о предоставлении асинхронного вычисления.

Он также представил один образец:

def listFiles = Action { implicit request =>
  val files = new java.io.File(".").listFiles
  Ok(files.map(_.getName).mkString(", "))
}

что является проблематичным, учитывая его использование блокирующего API java.io.File.

Здесь API java.io.File выполняет операцию блокирующего ввода-вывода, что означает, что один из немногих потоков пула веб-рабочих Play будет захвачен, а ОС отобразит список файлов в каталоге выполнения. Это такая ситуация, которую вы должны избегать любой ценой, потому что это означает, что у пула работников может закончиться поток.

-

Инструмент реактивного аудита, доступный https://github.com/octo-online/reactive-audit, направлен на то, чтобы указать блокирующие вызовы в проекте.

Надеюсь, что это тоже поможет.