遇到问题我还没找到答案。
使用Scala在playframework 2上运行。
需要编写执行多个Future调用的Action方法。 我的问题: 1)附加的代码是否是非阻塞的,因此看起来应该如何? 2)是否保证在任何给定时间都捕获两个DAO结果?
def index = Action.async {
val t2:Future[Tuple2[List[PlayerCol],List[CreatureCol]]] = for {
p <- PlayerDAO.findAll()
c <- CreatureDAO.findAlive()
}yield(p,c)
t2.map(t => Ok(views.html.index(t._1, t._2)))
}
感谢您的反馈。
答案 0 :(得分:6)
附加的代码是非阻塞的,因此看起来应该是这样吗?
这取决于一些事情。首先,我假设PlayerDAO.findAll()
和CreatureDAO.findAlive()
分别返回Future[List[PlayerCol]]
和Future[List[CreatureCol]]
。最重要的是这些功能实际上是自称的。他们是在进行JDBC调用,还是使用异步数据库驱动程序?
如果答案是JDBC(或其他一些同步数据库驱动程序),那么你仍然在阻塞,并且没有办法让它完全“非阻塞”。为什么?因为JDBC调用阻止了它们当前的线程,并且将它们包装在Future
中将无法解决这个问题。在这种情况下,您可以做的最多就是让它们阻止与Play用于处理请求的ExecutionContext
不同的ExecutionContext
。这通常是个好主意,因为如果你有几个并发运行的db请求,它们可以阻止用于处理HTTP请求的Play内部线程池,突然你的服务器必须等待处理其他请求(即使它们不需要)数据库调用)。
有关不同index
的更多信息,请参阅thread pools documentation和this answer。
如果你的回答是一个异步数据库驱动程序,比如反应性mongo(还有scalike-jdbc,也许还有其他一些),那么你的状态很好,我可能会让你阅读的内容比你不得不多了。在这种情况下,您的CreatureDAO.findAlive()
控制器功能将完全无阻塞。
是否可以保证在任何给定时间都捕获两个DAO结果?
我不太清楚你的意思。在您当前的代码中,您实际上是按顺序进行这些调用。在PlayerDAO.findAll()
返回之前,Future
不会执行。由于它们不相互依赖,似乎这不是故意的。要使它们并行运行,您应该在将它们映射到for-comprehension之前实例化def index = Action.async {
val players: Future[List[PlayerCol]] = PlayerDAO.findAll()
val creatures: Future[List[CreatureCol]] = CreatureDAO.findAlive()
val t2: Future[(List[PlayerCol], List[CreatureCol])] = for {
p <- players
c <- creatures
} yield (p, c)
t2.map(t => Ok(views.html.index(t._1, t._2)))
}
:
yield
唯一可以保证两个结果都完成的事情是Future
在t2.map(...)
完成之前(或者永远不会,如果失败的话)不执行,同样也是<{1}}完成后才会执行t2
。
进一步阅读:
Are there any benefits in using non-async actions in Play Framework 2.2?
Understanding the Difference Between Non-Blocking Web Service Calls vs Non-Blocking JDBC