async Action api如何在scala的play framework 2.2.x中运行?

时间:2015-08-06 12:51:50

标签: scala asynchronous playframework playframework-2.0 akka

我正在尝试创建异步api。但响应显示顺序执行。 完成的步骤:在两个chrome选项卡中打开url。然后快速地打击他们。 url ex: - localhost:9000/getStar

但执行日志如下: -

    [info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Ctrl+D to stop and go back to the console...)

[success] Compiled in 107ms
[info] application - Application has started
[info] play - Application started (Dev)
[info] application - Async started ************************** :tarun
[info] application - Success Async call  :1
[info] application - Success Async call  :2
[info] application - Success Async call  :3
[info] application - Success Async call  :4
[info] application - Success Async call  :5
[info] application - Success Async call  :6
[info] application - Success Async call  :7
[info] application - Success Async call  :8
[info] application - Success Async call  :9
[info] application - Async finished ************************** :tarun
[info] application - Async started ************************** :tarun1
[info] application - Success Async call  :1
[info] application - Success Async call  :2
[info] application - Success Async call  :3
[info] application - Success Async call  :4
[info] application - Success Async call  :5
[info] application - Success Async call  :6
[info] application - Success Async call  :7
[info] application - Success Async call  :8
[info] application - Success Async call  :9
[info] application - Async finished ************************** :tarun1

这个代码是:

package controllers

import play.Logger
import play.api.libs.json.Json
import play.api.mvc._


import scala.concurrent.Future

object StarController extends Controller {
  import play.api.libs.concurrent.Execution.Implicits.defaultContext


  def getStarAsync(name : String) = Action.async{
    val futureResult = Future{
      Logger.info("Async started ************************** :" + name)
      val a = 0;
      for( a <- 1 until 10) {
        Thread.sleep(1000)
        Logger.info("Success Async call  :" + a.toString)
      }
      Logger.info("Async finished ************************** :" + name)
      Map("success" -> Json.toJson(true), "msg" -> Json.toJson("Success Async by :" + name), "code" -> Json.toJson(200))
    }

    futureResult.map{ result =>
      Ok(Json.toJson(result))
    }
  }

}

任何人都可以帮助我理解,为什么即使使用异步调用也执行顺序?

3 个答案:

答案 0 :(得分:8)

Action.async不会神奇地使控制器方法异步。仅 的不同之处在于它需要Future[Result]而不是Result。而已。控制器本来是异步的,因为它们本质上是可能的(即正常的Action包裹在Future中。这里的事情是Thread.sleep(1000) 阻止它的线程,并且不是异步的。

另一件事是在开发模式(即activator run)中,播放服务器使用单个线程来处理请求,因此它可以正确处理重新加载/编译,演变等。所以发生的是你用同步调用阻止该线程。您应该使用activator start看到不同的结果,但即便如此,在此处使用Action.async也没有意义,除非您要将该阻止委托给其他线程池。

Further reading

答案 1 :(得分:1)

我做了很多实验,发现了一件事。也许这听起来很疯狂,但Play只有在从同一个浏览器到相同路径时才会顺序处理它们。如果我通过curl 从不同的浏览器或甚至从一个浏览器但到不同的路由发出请求,那么它们将被异步处理。不确定Play在这种方式下做了什么样的保护,但这种保护是存在的,这是事实。

答案 2 :(得分:0)

只是为了澄清m-z的答案。 这是如何处理代码中的一些异步集合的示例

def getStarAsyncOld(name: String) = Action.async {
  val futureResult = Future {
    Logger.info("Async started ************************** :" + name)
  } flatMap (_ => Future.sequence(for (a <- 1 until 10) yield Future {
    Thread.sleep(1000)
    Logger.info("Success Async call  :" + a.toString)
  })) map { _ =>
    Logger.info("Async finished ************************** :" + name)
    Map("success" -> Json.toJson(true), "msg" -> Json.toJson("Success Async by :" + name), "code" -> Json.toJson(200))
  }

  futureResult.map { result =>
    Ok(Json.toJson(result))
  }
}

或使用for绝对相同:

def getStarAsync(name: String) = Action.async {
  for {
    _ <- Future(Logger.info("Async started ************************** :" + name))
    _ <- Future.sequence(for (a <- 1 until 10) yield Future {
      Thread.sleep(1000)
      Logger.info("Success Async call  :" + a.toString)
    })
    _ = Logger.info("Async finished ************************** :" + name)
    result = Map("success" -> Json.toJson(true), "msg" -> Json.toJson("Success Async by :" + name), "code" -> Json.toJson(200))
  } yield Ok(Json.toJson(result))
}