Есть ли какие-либо преимущества в использовании не асинхронных действий в Play Framework 2.2?

Документация Play 2.2 гласит, что:

Из-за того, как работает Play, код действия должен быть максимально быстрым (т. Е. Неблокирующим). Так что же нам возвращать в качестве результата, если мы еще не можем его сгенерировать? Ответ - будущий результат!

Future[Result] будет в конечном итоге выкуплен значением типа Result. Предоставляя Future[Result] вместо обычного Result, мы можем быстро сгенерировать результат без блокировки. Тогда Play будет служить этому результату, как только обещание будет погашено.

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

Действия, которые возвращают будущее, созданы Action.asyncв отличие от Action.apply для нормальных, не асинхронных действий.

Есть ли польза от не асинхронных действий? Мне кажется, что лучший способ убедиться, что ни одно из моих действий не будет заблокировано, - это объявить их все, используя Action.async,

Фактически, согласно документации Play Framework 2.3, в Play 2.3 все выглядит так, что все действия асинхронные:

Примечание. Как Action.apply, так и Action.async создают объекты Action, которые обрабатываются одинаково. Существует один вид действий, который является асинхронным, а не два вида (синхронный и асинхронный). Конструктор.async - это просто средство для упрощения создания действий на основе API, которые возвращают будущее, что облегчает написание неблокирующего кода.

1 ответ

Решение

Просто потому, что вы могли бы использовать Action.async, не означает автоматически, что вы не блокируете. Все зависит от того, используете ли вы блокирующий API или нет.

Таким образом, Play 2.2 работает так же, как и Play 2.3. На самом деле нет разницы между Action.apply а также Action.asyncкроме своих подписей. Action.async ожидает некоторый блок кода, который возвращает Future[Result], в то время как Action.apply ожидает блок кода, который возвращает Result, Action.apply преобразует это block: => Result в Future[Result] просто позвонив Future.successful(block), (Перед звонком идет еще немного работы Future.successful, но это суть этого.)

Таким образом, варианты использования для каждого сводятся к API, который вы используете. Например, JDBC против ScalikeJDBC-async, блокирующие и неблокирующие API-интерфейсы базы данных. Допустим, вы выбираете пользователя из базы данных и отправляете его обратно клиенту как json.

Сигнатура типичной JDBC-поддерживаемой функции может выглядеть следующим образом (игнорируя ошибки для упрощения):

def read(id: Long): User

Ваша функция контроллера может выглядеть так:

def read(id: Long) = Action {
    Ok(Json.toJson(User.read(id))
}

Это примерно эквивалентно тому, что Action.apply делает:

def read(id: Long) = Action.async {
    Future.successful(Ok(Json.toJson(User.read(id)))
}

User.read однако блокирующий вызов JDBC по-прежнему блокируется, так что это не лучше, чем раньше.

Теперь предположим, что мы используем асинхронный вызов БД, который выглядит примерно так:

def read(id: Long): Future[User]

Функция контроллера будет выглядеть примерно так:

def read(id: Long) = Action.async {
    User.read(id).map(user => Ok(Json.toJson(user)))
}

Думайте об этом как о помощнике для использования API, которые возвращают Futures. Реальные преимущества приходят от реальных асинхронных реализаций этих API. Если вы застряли с блокирующим API (возможно, JDBC), есть и другие способы управления этим. Эта тема в списке рассылки Play - хорошая статья на эту тему: https://groups.google.com/forum/.

Другие вопросы по тегам