在Play Framework 2.2中使用非异步操作有什么好处吗?

时间:2014-06-02 14:51:36

标签: playframework playframework-2.2

Play 2.2 documentation表示:

  

由于Play的工作方式,动作代码必须尽可能快(即非阻塞)。那么如果我们还不能生成它,我们应该返回什么呢?回应是未来的结果!

     

未来[结果]最终将使用Result类型的值进行兑换。通过给出Future [Result]而不是普通Result,我们可以快速生成结果而不会阻塞。然后,Play将在兑换承诺后立即提供此结果。

     

在等待响应时将阻止Web客户端,但服务器上不会阻止任何内容,服务器资源可用于为其他客户端提供服务。

返回Future的操作创建Action.async,而不是Action.apply,用于正常的非异步操作。

使用非异步操作有什么好处吗?令我感到震惊的是,确保我的所有操作都不会阻止的最佳方法是使用Action.async声明所有操作。

事实上,根据Play {2}中的Play Framework 2.3 documentation,所有操作都是异步的:

  

注意:Action.apply和Action.async都会以相同的方式创建内部处理的Action对象。有一种Action是异步的,而不是两种(同步的和异步的)。 .async构建器只是简化基于返回Future的API创建操作的工具,这使得编写非阻塞代码变得更加容易。

1 个答案:

答案 0 :(得分:12)

仅仅因为您可能使用Action.async,并不自动意味着您没有阻止。这完全取决于您是否使用阻止API。

Play 2.2似乎与Play 2.3的工作方式相同。除了签名之外,Action.applyAction.async之间并没有什么区别。 Action.async需要一些返回Future[Result]的代码块,而Action.apply需要一段返回Result的代码。 Action.apply只需拨打block: => Result即可将Future[Result]转换为Future.successful(block)。 (在调用Future.successful之前还有一些工作要做,但这是它的要点。)

因此,每个用例都归结为您正在使用的API。例如JDBC vs 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)))
}

将其视为使用返回Future的API的助手。真正的好处来自这些API的实际异步实现。如果您遇到阻塞API(可能是JDBC),还有其他方法可以对其进行管理。 Play邮件列表上的这个主题是关于这个主题的好读物:https://groups.google.com/forum/#!topic/play-framework/WWQ0HeLDOjg