Playframework非阻塞动作

Tho*_*aus 0 scala akka playframework

碰到一个问题我还没找到答案.

使用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)))
}
Run Code Online (Sandbox Code Playgroud)

感谢您的反馈意见.

Mic*_*jac 6

附加的代码是否是非阻塞的,因此看起来应该是这样的?

这取决于一些事情.首先,我要假设PlayerDAO.findAll()CreatureDAO.findAlive()返回Future[List[PlayerCol]]Future[List[CreatureCol]]分别.最重要的是这些功能实际上是自称的.他们是在进行JDBC调用,还是使用异步数据库驱动程序?

如果答案是JDBC(或其他一些同步数据库驱动程序),那么你仍然在阻塞,并且没有办法让它完全"非阻塞".为什么?因为JDBC调用会阻止它们当前的线程,并且将它们包装在一个Future将无法修复它.在这种情况下,您可以做的最多就是让它们阻止ExecutionContext与Play用于处理请求的块不同.这通常是个好主意,因为如果你有几个并发运行的db请求,它们可以阻止用于处理HTTP请求的Play内部线程池,突然你的服务器必须等待处理其他请求(即使它们不需要)数据库调用).

有关不同ExecutionContexts的更多信息,请参阅线程池文档此答案.

如果你的答案是一个异步数据库驱动程序,如反应性mongo(也有scalike-jdbc,也许还有其他一些),那么你的状态很好,我可能会让你读到比你更多的东西.在那种情况下,您的index控制器功能将完全无阻塞.

是否可以保证在任何给定时间捕获两个DAO结果?

我不太清楚你的意思.在您当前的代码中,您实际上是按顺序进行这些调用.返回CreatureDAO.findAlive()后才执行PlayerDAO.findAll().由于它们不相互依赖,似乎这不是故意的.要使它们并行运行,您应该Future在将它们映射到for-comprehension之前实例化s:

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)))
}
Run Code Online (Sandbox Code Playgroud)

关于完成两个结果,你唯一可以保证的是,yieldFutures完成之前(或者从不,如果它们失败)t2.map(...)不会执行,同样在t2完成之前不会执行主体.


进一步阅读:

在Play Framework 2.2中使用非异步操作有什么好处吗?

了解非阻止Web服务调用与非阻止JDBC之间的区别