Handling asynchronous results【翻译】

原文:Handling asynchronous results

让控制器变成异步的

本质上,Play Framework从里到外都是异步的。Play以异步,非阻塞方式处理每一个请求。

默认配置已经为异步控制器做了优化。也就是说,在控制器中,应用代码应该避免阻塞,例如,让控制器代码等待一个操作。这种常见的阻塞操作的例子有JDBC调用,流式API,HTTP请求和长时间的计算。

尽管在默认的执上下文中可以增加线程的数量,让更多并发请求处在阻塞中的控制器执行,但是按照保持控制器异步的推荐方法,可以让线程数据更容易调整并在负载下保证系统的响应。

创建非阻塞Action

由于Play的工作方式,Action代码执行必须尽可能的快,例如,非阻塞。因此,如果我们还不能生产结果,那么我们应该返回什么作为结果呢?答案是一个future 结果!

Future[Result]最终将被用 Result类型的值回填。通过给定的 Future[Result] 代替正常的结果,我可以很快的生成结果而不阻塞。一旦执行完成,Play就会返回结果。

当等待应答时,网络客户端将被阻塞,但是在服务端没有什么会被阻塞,服务端的资源,可以被用来服务其他客户端。

怎样创建Future[Result]

为了创建 Future[Result] ,首先我们还需要一个Future,这个Future将会给我们一个需要计算结果的真实值:

import play.api.libs.concurrent.Execution.Implicits.defaultContext

val futurePIValue: Future[Double] = computePIAsynchronously()
val futureResult: Future[Result] = futurePIValue.map { pi =>
Ok("PI value computed: " + pi)
}

Play所有的异步API调用,都会返回给你一个Future。无论你是使用play.api.libs.WS API调用一个外部的Web服务,还是使用Akka 调度一个异步的任务或使用play.api.libs.Akka和Actor通信,都是这样。 这是异步执行的一段代码并得到Future的简单方式:

val futureInt: Future[Int] = scala.concurrent.Future {
intensiveComputation()
}

注意:重要的是理解哪个线程代码运行返回Future。在上面的两段代码块中,导入了Play默认的执行环境。这是一个隐式的参数,这个参数传递到所有Future API上接受回调的方法。尽管不一定,但是多数情况下执行上下文相当于线程池。

你不可能只通过在Future中封装就魔术般的把同步线程转成异步的。如果你不能改变应用的架构来避免阻塞操作,在某一时刻操作就一定会被执行,然后线程将会阻塞。 因此为了在Future中封装操作,有必要配置它,让它运行到一个独立的执行上下文中,这个上下文配置了足够多的线程来运行预期的并发。详见 理解Play线程池

使用Actor处理阻塞操作也是有用的。Actor为处理超时和失败提供了一个清理模式,设置阻塞执行上下文,并管理任何可能与服务相关的状态。Actor还提供了类似ScatterGatherFirstCompletedRouter 的模式在一组后端服务器上同时处理缓存和数据库请求并允许远程执行。但是Actor 也许过度的依赖你需要的。

返回Future

到目前为止,虽然我们使用Action.apply构建方法构建Action,但是我们需要使用 Action.async 构建方法来发送一个异步的结果:

import play.api.libs.concurrent.Execution.Implicits.defaultContext

def index = Action.async {
val futureInt = scala.concurrent.Future { intensiveComputation() }
futureInt.map(i => Ok("Got result: " + i))
}

Action默认是异步的

默认情况下,Play的Action是异步的。例如,在下面的控制器代码中,代码的{ Ok(...) } 部分不是控制器的方法体。它是一个被传递到Action对象的apply 方法的匿名函数,它会创建一个Action类型的对象。本质上,你写的匿名函数将会被调用,并且它的结果会被封装到 Future。

def echo = Action { request =>
Ok("Got request [" + request + "]")
}

注意:Action.apply 和Action.async 都创建Action对象,它们的本质是相同的。有一种单一的Action,它是异步的,不是两种(一种是异步的,一种是同步的)。 .async 构建器只是一个基于返回Future的API,简化创建Action的工具,它可以让开发更容易写非阻塞的代码。

处理超时

通常为了避免如果有什么错误而导致的Web浏览器阻塞并等待, 适当的处理超时很有用。你可以使用 play.api.libs.concurrent.Timeout 在非阻塞超时中封装Future :

import play.api.libs.concurrent.Execution.Implicits.defaultContext
import scala.concurrent.duration._
import play.api.libs.concurrent.Timeout

def index = Action.async {
Timeout.timeout(actorSystem, 1.seconds) {
intensiveComputation().map { i =>
Ok("Got result: " + i)
}
}.recover {
case e: TimeoutException =>
InternalServerError("timeout")
}
}

注意:超时不同于取消——即使在超时的情况下,给定的Future仍将完成,哪怕完成的值没有返回。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,106评论 6 542
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,441评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,211评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,736评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,475评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,834评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,829评论 3 446
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,009评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,559评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,306评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,516评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,038评论 5 363
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,728评论 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,132评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,443评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,249评论 3 399
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,484评论 2 379

推荐阅读更多精彩内容