如何实施ReactiveMongo以使其被视为非阻塞?

时间:2014-09-02 07:40:44

标签: scala playframework reactive-programming reactivemongo iterate

阅读有关Play Framework和ReactiveMongo的文档让我相信ReactiveMongo的工作方式是它使用少量线程而且永远不会阻塞。

然而,似乎从Play应用程序到Mongo服务器的通信必须发生在某处某个线程上。这是如何实现的? Play,ReactiveMongo,Akka等源代码的链接也将非常受欢迎。

Play Framework在此页about thread pools中包含一些有关此内容的文档。它开始于:

  

Play框架是自下而上的异步Web框架。使用迭代器异步处理流。 Play中的线程池被调整为使用比传统Web框架更少的线程,因为play-core中的IO永远不会阻塞。

然后谈谈ReactiveMongo:

  

典型Play应用程序阻止的最常见位置是它与数据库通信时。遗憾的是,没有一个主要数据库为JVM提供异步数据库驱动程序,因此对于大多数数据库,您唯一的选择是使用阻塞IO。一个值得注意的例外是ReactiveMongo ,这是一个使用Play的Iteratee库与MongoDB通信的MongoDB驱动程序。

以下是关于使用期货的说明:

  

请注意,您可能想要将阻止代码包装在Futures中。这不会使它成为非阻塞,只是意味着阻塞将在不同的线程中发生。您仍然需要确保您在那里使用的线程池有足够的线程来处理阻塞。

页面Handling Asynchronous Results上的Play文档中有类似的说明:

  

通过将同步IO包装在Future中,您无法神奇地将同步IO变为异步。如果您无法更改应用程序的体系结构以避免阻塞操作,那么某些时候必须执行操作,并且该线程将阻止。因此,除了将操作封装在Future中之外,还需要将其配置为在单独的执行上下文中运行,该上下文已配置了足够的线程来处理预期的并发。

文档似乎在说ReactiveMongo是非阻塞的,因此您不必担心它会占用线程池中的大量线程。但ReactiveMongo必须与Mongo服务器在某处进行通信。

如何实现此通信,以便Mongo不会使用Play的默认线程池中的线程?

再次,非常感谢PlayReactiveMongoAkka等特定文件的链接。

1 个答案:

答案 0 :(得分:11)

是的,确实,您仍然需要使用线程来执行任何类型的工作,包括与数据库的通信。重要的是这种沟通的确切方式

ReactiveMongo“不使用线程”,因为它不使用阻止I / O 。像java.io.InputStream这样的常用Java I / O工具正在阻塞;这意味着从这样的InputStream读取或写入OutputStream会阻塞该线程,直到“另一方”提供所需数据或准备接受它为止。对于网络通信,这意味着将阻止 线程。

但是,Java提供了NIO API,它支持非阻塞异步 I / O.我现在不想深入了解其细节,但基本思路当然是非阻塞I / O允许不阻止需要与外界交换某些数据的线程:例如,这些线程可以轮询数据源以检查是否有可用的数据,如果没有,则返回到线程池并可用于其他任务。当然,在那里,这些设施由底层操作系统提供。

非阻塞I / O的确切实现细节通常隐藏在像Netty这样的高级库中,因为它使用起来并不好。例如,Netty(正是ReactiveMongo使用的库)提供了很好的异步回调式API,它非常易于使用,但功能强大且足够强大,可以构建具有高吞吐量的复杂I / O密集型应用程序。 p>

因此,ReactiveMongo使用Netty与Mongo数据库服务器通信,并且由于Netty是异步网络I / O的实现,ReactiveMongo实际上不需要长时间阻塞线程。