async Action api 如何在 play framework 2.2.x for scala 中工作?
How async Action api works in play framework 2.2.x for scala?
我正在尝试创建异步 api。但响应显示顺序执行。
完成的步骤: 在 chrome 的两个选项卡中打开 url。并迅速将他们一个接一个地击中。 url 例如:- 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))
}
}
}
任何人都可以帮助我理解,为什么即使使用异步调用也是顺序执行的?
Action.async
不会神奇地使控制器方法异步。 only 它的不同之处在于它需要 Future[Result]
而不是 Result
。而已。控制器在其他方面是异步的,因为它们本质上是异步的(即一个普通的 Action
无论如何都会被包裹在 Future
中)。这里的问题是 Thread.sleep(1000)
阻塞 它是线程,一点也不异步。
另一件事是,在开发模式下(即activator run
),播放服务器使用单线程来处理请求,因此它可以正确处理reload/compile、进化等。那是什么发生的是你只是用同步调用阻塞了那个线程。使用 activator start
应该会看到不同的结果,但即便如此,在这里使用 Action.async
也毫无意义,除非您要将该阻塞委托给不同的线程池。
Further reading.
只是为了澄清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))
}
我做了很多实验,发现了一件事。也许这听起来很疯狂,但 Play 仅在 从同一浏览器到同一路由 时才按顺序处理并发请求。如果我通过 curl 或 从不同的浏览器 甚至从一个浏览器 向不同的路由 发出请求,然后他们被异步处理。不知道Play以这种方式做了什么样的保护,但这种保护存在并且是事实。
我正在尝试创建异步 api。但响应显示顺序执行。
完成的步骤: 在 chrome 的两个选项卡中打开 url。并迅速将他们一个接一个地击中。 url 例如:- 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))
}
}
}
任何人都可以帮助我理解,为什么即使使用异步调用也是顺序执行的?
Action.async
不会神奇地使控制器方法异步。 only 它的不同之处在于它需要 Future[Result]
而不是 Result
。而已。控制器在其他方面是异步的,因为它们本质上是异步的(即一个普通的 Action
无论如何都会被包裹在 Future
中)。这里的问题是 Thread.sleep(1000)
阻塞 它是线程,一点也不异步。
另一件事是,在开发模式下(即activator run
),播放服务器使用单线程来处理请求,因此它可以正确处理reload/compile、进化等。那是什么发生的是你只是用同步调用阻塞了那个线程。使用 activator start
应该会看到不同的结果,但即便如此,在这里使用 Action.async
也毫无意义,除非您要将该阻塞委托给不同的线程池。
Further reading.
只是为了澄清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))
}
我做了很多实验,发现了一件事。也许这听起来很疯狂,但 Play 仅在 从同一浏览器到同一路由 时才按顺序处理并发请求。如果我通过 curl 或 从不同的浏览器 甚至从一个浏览器 向不同的路由 发出请求,然后他们被异步处理。不知道Play以这种方式做了什么样的保护,但这种保护存在并且是事实。