1.创建异步的controller

Play是一个自底向上的异步框架,play处理所有的request都是异步、非阻塞的。默认的方式是使用异步的controller。换句话说,contrller中的应用代码需要避免阻塞,i.e.不能等待某一个操作。

场景的阻塞操作有JDBC调用、streaming API、HTTP请求和耗时计算。虽然可以通过增加线程池中线程的数量来让阻塞的controller处理更多的请求。还是通过以下建议使controller异步来保持程序的可靠性和可扩展性。

2.创建非阻塞的action

在Play的机制中,action需要尽可能的块,非阻塞。如果还没有生成,就返回一个future 结果。A Future[Result]最终会被Result类型的值兑换。通过给出一个Future[Result]而不是一个正常的Result,我们能够快速生成结果,没有阻塞。

一旦兑换完成,play将立即提供result。Web客户端在等待响应时将阻塞,但服务器上不会阻塞,并且服务器资源可用于为其他客户端提供服务。使用Future只是完成了一半!调用诸如JDBC之类的阻塞API,

仍需要让ExecutionStage与其他执行器一起运行,以将其从Play的线程池中移出。您可以通过创建一个play.api.libs.concurrent.CustomExecutionContext的、带有对自定义调度程序引用的子类来完成此操作

import play.api.libs.concurrent.CustomExecutionContext

trait MyExecutionContext extends ExecutionContext

class MyExecutionContextImpl @Inject()(system: ActorSystem)
extends CustomExecutionContext(system, "my.executor") with MyExecutionContext class HomeController @Inject()(myExecutionContext: MyExecutionContext, val controllerComponents: ControllerComponents) extends BaseController {
def index = Action.async {
Future {
// Call some blocking API
Ok("result of blocking call")
}(myExecutionContext)
}
}

有关使用自定义执行上下文的更多信息,请参阅ThreadPools。

3.创建一个Future[Result]

为了创造一个Future[Result]我们首先需要另一个future,它将给我们计算结果所需的实际值

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()}

注意:知道哪个线程运行着futures很重要,在上面的两个代码块中,Plays默认执行环境中有一个导入。这是一个隐式参数,被传递给future API上的所有方法,来接受回调。执行环境通常是一个线程池,即使不必要。如果不能改变应用程序的体系结构以避免阻塞操作,

除了关闭一个Future的操作外,还需要将其配置为在单独的执行环境文中运行,配置足够的线程以处理预期的并发。请参阅了解播放线程池以获取更多信息,并下载显示数据库集成的播放示例模板。对于阻塞操作来说使用actor也是很有帮助的。

Actor提供了一个干净的模型来处理超时和失败,设置阻塞执行环境以及管理可能与服务关联的状态。Actors也提供模式ScatterGatherFirstCompletedRouter来解决同时缓存和数据库请求,并允许在后端服务器集群上远程执行。

4.返回futures

之前我们使用Action.apply来构建actions,要发送异步结果,我们需要使用Action.async构建器方法

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

5.Actions默认是异步的

在下面的代码中,代码的{ Ok(...) }部分不是controller的方法体。它是传递给Action对象apply方法的匿名函数,它创建一个Action对象。在内部,你编写的匿名函数将被调用,其结果将被包含在一个Future中。

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

6.超时问题

正确处理超时通常很有用,为了避免Web浏览器阻塞,并在出现问题时等待,可以使用play.api.libs.concurrent.Futures

import scala.concurrent.duration._
import play.api.libs.concurrent.Futures._ def index = Action.async {
// You will need an implicit Futures for withTimeout() -- you usually get
// that by injecting it into your controller's constructor
intensiveComputation().withTimeout(1.seconds).map { i =>
Ok("Got result: " + i)
}.recover {
case e: scala.concurrent.TimeoutException =>
InternalServerError("timeout")
}
}

超时与取消并不相同, – 超时的情况下计算仍然会继续,尽管结果不会返回

PLAY2.6-SCALA(六) 异步处理结果的更多相关文章

  1. Scala(六)【模式匹配】

    目录 一.基本语法 二.匹配固定值 三.守卫 四.匹配类型 五.匹配集合 1.Array 2.List 3.元祖 4.对象和样例类 六.偏函数 七.赋值匹配 八.for循环匹配 一.基本语法 在匹配某 ...

  2. play1.x vs play2.x 对比(转)

    个人看到对比play1.x和play2.x比较的文章中,写的最深入,最清晰的一个.转自:http://freewind.me/blog/20120728/965.html 为了方便群中的Play初学者 ...

  3. 混合使用ForkJoin+Actor+Future实现一千万个不重复整数的排序(Scala示例)

    目标       实现一千万个不重复整数的排序,可以一次性加载到 2G 的内存里. 本文适合于想要了解新语言 Scala 并发异步编程框架 Akka, Future 的筒鞋. 读完本文后,将了解如何综 ...

  4. Scala新版本学习(1):

    1.进官网:https://www.scala-lang.org/ 上面就是进入Scala社区后的一个画面,官方对Scala的简单介绍是:Scala将面向对象和函数式编程集合在一个简洁的高级语言中,S ...

  5. Akka系列(五):Java和Scala中的Future

    前言....... 随着CPU的核数的增加,异步编程模型在并发领域中的得到了越来越多的应用,由于Scala是一门函数式语言,天然的支持异步编程模型,今天主要来看一下Java和Scala中的Futrue ...

  6. 【原创】kafka producer源代码分析

        Kafka 0.8.2引入了一个用Java写的producer.下一个版本还会引入一个对等的Java版本的consumer.新的API旨在取代老的使用Scala编写的客户端API,但为了兼容性 ...

  7. 追源索骥:透过源码看懂Flink核心框架的执行流程

    li,ol.inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt, ...

  8. 给Java开发人员的Play Framework(2.4)介绍 Part1:Play的优缺点以及适用场景

    1. 关于这篇系列 这篇系列不是Play框架的Hello World,由于这样的文章网上已经有非常多. 这篇系列会首先结合实际代码介绍Play的特点以及适用场景.然后会有几篇文章介绍Play与Spri ...

  9. 透过源码看懂Flink核心框架的执行流程

    前言 Flink是大数据处理领域最近很火的一个开源的分布式.高性能的流式处理框架,其对数据的处理可以达到毫秒级别.本文以一个来自官网的WordCount例子为引,全面阐述flink的核心架构及执行流程 ...

随机推荐

  1. response - 文件下载

    ## 案例:     * 文件下载需求:         1. 页面显示超链接         2. 点击超链接后弹出下载提示框         3. 完成图片文件下载 * 分析:         1 ...

  2. JSP-案例-商品增删改

    商品的增删改查 1显示 部分代码 Dao public List<Product> findAllProduct() throws SQLException { QueryRunner r ...

  3. hbase 利用rowkey设计进行多条件查询

    摘要 本文主要内容是通过合理Hbase 行键(rowkey)设计实现快速的多条件查询,所采用的方法将所有要用于查询中的列经过一些处理后存储在rowkey中,查询时通过rowkey进行查询,提高rowk ...

  4. java随机生成字符串工具类

    package aA; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; /** * 字符随机 ...

  5. springmvc:常用注解

    一.RequestParam注解 作用: 把请求中指定名称的参数给控制器中的形参赋值. 属性: value:请求参数中的名称. required:请求参数中是否必须提供此参数.默认值:true.表示必 ...

  6. Leetcode173. Binary Search Tree Iterator二叉搜索树迭代器

    实现一个二叉搜索树迭代器.你将使用二叉搜索树的根节点初始化迭代器. 调用 next() 将返回二叉搜索树中的下一个最小的数. 注意: next() 和hasNext() 操作的时间复杂度是O(1),并 ...

  7. useradd -M -s /sbin/nologin mysql -g mysql 报错 Creating mailbox file

    由于之前使用以下命令删除了mysql账户 userdel mysql groupdel mysql      #如果删除了mysql用户,对应的组也会被删除(只有一个用户的情况下) 执行以下命令时报错 ...

  8. 【python之路28】模块python与excel

    一.可使用的第三方库 python中处理excel表格,常用的库有xlrd(读excel)表.xlwt(写excel)表.openpyxl(可读写excel表)等.xlrd读数据较大的excel表时效 ...

  9. Laravel 5.4: 特殊字段太长报错 420000 字段太长

    laravel 5.4 改变了默认的数据库字符集,现在utf8mb4包括存储emojis支持.如果你运行MySQL v5.7.7或者更高版本,则不需要做任何事情. 当你试着在一些MariaDB或者一些 ...

  10. 中介者模式(Mediator、ConcreteMediator、Colleague Class)(租房中介)

    中介者模式就是利用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地互相引用,从而使其耦合松散,而且可以独立地改变他们之间的交互. 就像租房的中介系统,房主跟租房者不需要知道彼此只需要,只 ...