• PLAY2.6-SCALA(六) 异步处理结果


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

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

  • 相关阅读:
    Java annotation
    子类 父类强转 HttpServlet service实现
    父类 子类 强转
    HttpServlet Service方法
    java go
    IO写 PrintWriter
    IO读 BufferedReader+FileReader
    Java NIO-3
    心跳包(HeartBeat)
    Git学习笔记(一)
  • 原文地址:https://www.cnblogs.com/feiyumo/p/9144055.html
Copyright © 2020-2023  润新知