【问题标题】:Play Framework + JDBC + FuturesPlay Framework + JDBC + Futures
【发布时间】:2016-11-25 04:58:31
【问题描述】:
假设我通过注入获得了 JDBC 连接,如下所示:
class SqlQuery @Inject()(db: Database) extends Controller { /* .... */ }
并且连接池足够大,例如100。是否可以创建一个Future以避免在运行SQL语句时阻塞(类似于Slick futures)?还是说池中的连接数很大,说明SQL语句不会阻塞?
【问题讨论】:
标签:
scala
playframework
slick
slick-3.0
【解决方案1】:
使用期货并不是非阻塞的同义词。通常,Futures 允许您在另一个线程或某种类型的执行器上执行代码。但是,您执行的代码仍然可以阻塞。
JDBC 是一个阻塞 API。这意味着当您通过 JDBC 执行查询时,调用线程在等待来自数据库的响应时被阻塞。另一个术语是同步。非阻塞或异步 API 将异步接受响应,从而将调用线程从主动等待中释放出来。 Reactive slick 使用它自己的驱动程序以异步方式接受来自数据库的响应,这意味着只要将查询分派到数据库,就可以释放调用线程。
两者的区别是这样的:
假设您的应用程序有一个大小为 100 的数据库连接池和一个大小为 10 的固定线程池。然后,假设您将所有 JDBC 调用包装在期货中。假设您的SqlQuery 控制器有一个方法可以同时进行多个JDBC 调用。所有这些查询将并行运行,直到线程池耗尽,这意味着您在任何给定时刻只能同时运行 10 个查询。虽然调用线程不会被 JDBC 调用阻塞,但执行它们的线程会阻塞。并行运行足够多的查询时,线程池将耗尽,池中的连接数不再重要。您可以通过使线程池更大或使用根据需要扩展的分叉连接池来解决此问题,但这可能会由于创建新线程和上下文切换而导致性能成本。毕竟,你的 CPU 是有限的。
使用像响应式 slick 这样的异步数据库驱动程序不会阻塞有限的线程池,并且您可以同时运行与池中连接数一样多的查询(本例中为 100 个)。避免线程被阻塞意味着节省 CPU 时间,否则将花费在等待响应上,这意味着您可以使用它来继续处理其他请求等。