我正在使用Play 2.5和Slick。关于此主题的docs只是声明一切都由Slick和Play的Slick模块管理。但是,此示例打印Dispatcher[akka.actor.default-dispatcher]
:
class MyDbioImpl @Inject()(protected val dbConfigProvider: DatabaseConfigProvider)(implicit ec: ExecutionContext)
with HasDatabaseConfigProvider[JdbcProfile] {
import profile.api._
def selectSomeStuff(): Future[MyResult] = db.run {
println(ec)
[...]
}
}
由于执行上下文打印在db.run中,似乎我的所有数据库访问也将在默认执行上下文中执行。
我找到this answer一个较旧的问题,当时解决了这个问题。但是这个解决方案已被弃用,建议使用依赖注入来获取应用程序上下文。当我尝试这样做时,我得到一个错误,说play.akka.actor.slick-context不存在......
class MyDbioProvider @Inject()(actorSystem: ActorSystem,
protected val dbConfigProvider: DatabaseConfigProvider)
extends Provider[MyDbioImpl] {
override def get(): MyDbioImpl = {
val ec = actorSystem.dispatchers.lookup("play.akka.actor.slick-context")
new MyDbioImpl(dbConfigProvider)(ec)
}
}
编辑:
Slick的执行上下文是否是在某个配置文件中定义的“正常”执行上下文?上下文切换发生在哪里?我认为“数据库世界”的入口点是db.run
。
答案 0 :(得分:2)
根据Slick:
每个数据库都包含一个管理线程池的AsyncExecutor 用于异步执行数据库I / O操作。它的大小是 调整数据库最佳性能的主要参数 宾语。它应该设置为您将用于大小的值 传统的阻塞应用程序中的连接池(请参阅 关于HikariCP文档中的池大小调整以进一步了解 信息)。使用Database.forConfig时,线程池是 直接在外部配置文件中配置 连接参数。如果您使用任何其他工厂方法来获取 在数据库中,您可以使用默认配置或指定 自定义AsyncExecutor。
基本上它表示你不需要创建一个独立的ExecutionContext,因为Slick已经在内部隔离了一个线程池。您对Slick的任何调用都是非阻塞的,因此您应该使用默认的ExecutionContext。
答案 1 :(得分:0)
Slick的此实现可在BasicBackend.scala文件:runInContextSafe方法中看到。代码如下:
val promise = Promise[R]
val runnable = new Runnable {
override def run() = {
try {
promise.completeWith(runInContextInline(a, ctx, streaming, topLevel, stackLevel = 1))
} catch {
case NonFatal(ex) => promise.failure(ex)
}
}
}
DBIO.sameThreadExecutionContext.execute(runnable)
promise.future
如上所示,此处使用Promise,然后使用其内部线程池快速执行其代码,并返回Promise的Future对象。因此,当执行Await.result / ready时,此处的Promise可能已经由Slick的内部线程执行,因此获取结果就足够了,并且可以在诸如Play的环境中执行Await.result / ready。不阻塞的。
有关详细信息,请参阅Scala关于“未来与承诺”的文档:https://docs.scala-lang.org/overviews/core/futures.html