我试图在概念上理解为什么在Play Framework 2.0中,将WS.url().get()
称为Web服务调用被视为最佳实践,但是如果您将任何其他阻塞调用(例如JDBC调用)包装起来一个promise,建议你在默认执行上下文以外的执行上下文中执行它?
据我所知,默认情况下,Play Framework的线程池配置为每个核心有一个线程,每个控制器都希望运行完全无阻塞的代码。因此,如果您在控制器中进行阻塞调用(例如,对Web服务),那么您需要确保此调用不会阻止可用于控制器的线程。
否则,没有线程可以执行控制器,因为它们都处于阻塞状态等待。
但令我困惑的是以下几点:
WS.url().get()
也在默认执行上下文中执行,但另一方面,Play Framework Documentation on Thread Pool Configuration表示"请注意,您可以被诱惑...将您的阻止代码包装在期货中。这不会阻止它,它只是意味着阻塞将在不同的线程中发生。" 上述意思不是WS.url().get()
是"只是发生在不同的线程"在相同的默认执行上下文中?在不同的执行上下文中执行JDBC调用有什么不同?
答案 0 :(得分:5)
1)播放控制器功能在Play的默认线程池中执行,如链接文档中所述:
播放默认线程池 - 这是默认线程池,其中执行Play Framework中的所有应用程序代码。它是Akka调度程序,可以通过配置Akka进行配置,如下所述。默认情况下,每个处理器有一个线程。
因此,您需要非常小心阻塞控制器函数,因为这会阻塞默认线程池中的线程。
2)播放网络服务是一种非阻止API,因此不会阻止它ExecutionContext
。因此,可以在控制器函数中进行多次WS调用,而不会阻塞默认线程池。 WS调用和JDBC调用之间的主要区别在于WS调用在等待来自远程服务器的响应时不会阻塞线程,这些调用是异步调用的。 JDBC调用(像大多数java IO一样)会在等待响应时阻塞它的线程。
在另一个ExecutionContext
内执行JDBC调用将释放默认ExecutionContext
以执行其他工作,从而允许您的服务器处理更多请求。您可以让Akka为您处理上下文切换的艰苦工作。虽然JDBC调用仍然阻塞了一个线程,但它们至少不会阻塞处理请求的线程。