Handling asynchronous results

    默认配置下controller即是异步的了。换言之,应用应该避免在controller中做阻塞操作,例如,让controller等待某一个操作完成。类似的阻塞操作还有:调用JDBC,流处理(streaming)API,HTTP请求和长时间的计算任务。

    虽然不可能通过增加默认执行环境(execution context)中的线程数来提升阻塞controller的并发请求处理能力,但使用异步controller可以使应用更易于扩展,在负载较大的情况下依然能够保持响应。

    创建非阻塞action

    由于Play的异步工作方式,action应该做到尽可能的快,例如非阻塞。那么,在还没有得到返回结果的情况下,应该返回什么作为结果呢?答案是future结果!

    一个Future[Result]最终会被替换成一个类型为Result的值。通过提供Future[Result]而非Result,我们能够在非阻塞的情况下快速生成结果。一旦从promise中得到了最终结果,Play就会应用该结果。

    在创建一个Future[Result]之前,我们需要先创建另一个future:这个future会返回一个真实的值,以便我们依此生成结果:

    所有的Play异步API调用都会返回一个Future。不管你是在调用外部web服务,如play.api.libs.WSAPI,或是用Akka调度异步任务,亦或是使用与actor进行通讯。

    以下是一个异步调用并获得一个Future的简单例子:

    注意:理解哪个线程运行了future非常重要,以上的两段代码都导入了Play的默认执行环境(execution context)。这是一个隐式(implicit)的参数,会被传入所有接受回调的future API方法中。执行环境(execution context)通常等价于线程池,但这并不是一定的。

    这对于使用Actor来阻塞操作也非常有用。Actor提供了一种非常简洁的模型来处理超时和失败,设置阻塞执行环境(execution context),并且管理了该服务的一切状态。Actor还提供了像ScatterGatherFirstCompletedRouter这样的模式来处理同时缓存和数据库请求,并且能够远程执行于后端服务器集群中。但使用actor可能有些多余,主要还是取决你想要的是什么。

    返回future

    迄今为止,我们一直都在调用Action.apply方法来构建action,为了发出一个异步的结果,我们需要调用Action.async

    Play的action默认即是异步的。比如说,在下面这个controller中,{ Ok(...) }这部分代码并不是controller的方法体。这其实是一个传入Action对象方法的匿名函数,用来创建一个Action对象。运行时,你写的这个匿名函数会被调用并返回一个Future结果。

    注意:Action.applyAction.async创建的Action对象在Play内部会以同样的方式处理。他们都是异步的Action,而不是一个同步一个异步。.async构造器只是用来简化创建基于API并返回Future的action,让非阻塞的代码更加容易写。

    处理超时