1

最近我开始学习非阻塞 Java 框架,其中有一个引起了我的注意reactive- .event-drivenvert.x

我想同样的问题可能适用于akka(Play 框架),因为他们的理念或目标之一是相同的——那就是减少线程数,从而提高应用程序的可扩展性

vert.x建议它消耗的线程数〜相当于 CPU 内核的数量,但它也牢记有时您必须执行阻塞操作,因此它鼓励开发人员在单独的工作线程上执行阻塞操作(工人垂直于vert.x 的条款)。

这就是我们提出我的问题的地方:

  • 如果我应该在一个新的单独线程上执行阻塞 IO 操作,这意味着每个执行阻塞操作的用户都有一个新线程,因此线程数再次等于经典阻塞线程模型中的用户数?

一个真实的例子是 JDBC 查询——如果 1000 个并发用户通过 JDBC 查询一个 SQL 数据库,每个用户都会为该阻塞操作生成它自己的工作线程。从我的角度来看,与经典的阻塞线程模型相比,没有线程备用、改进的可扩展性或 RAM 备用。我一定是错过了什么……或者没有?提前感谢所有答案。

4

4 回答 4

2

生成 1000 个并发线程来查询 SQL 数据库是没有意义的——仅仅因为典型的数据库不能承受这么多的同时连接,典型的数量是 10-15。解决方案是组织一个特殊的线程池,每个线程都有一个开放的连接并服务于访问数据库的任务。任务被提交到一个公共阻塞队列,工作线程从该队列中循环读取。任务是

interface DBRunnable {
  public void run(Connection conn);
}

工作线程将它们的连接传递给任务:

public void run() {
  Connection conn = DriverManager.getConnection(...);
  while (true) {
     DBRunnable task=queue.take();
     task.run(conn);
  }
}
于 2014-03-14T18:50:22.373 回答
0

vert.x 建议在机器上运行线程而不是用户。

他们的意思是,如果你有 16 个 CPU 内核可用并且有 16 个准备工作的线程,那么如果你在其中一个上运行阻塞操作,那么最多只有 15 个线程保持工作,因此你的 CPU 内核只有 15 个实际上正在工作。您的 1 个核心正在等待!

因此,为了防止拥有一个空闲内核,他们建议您再创建一个线程并为其分配阻塞任务,这样您的 16 个 CPU 内核上仍有 16 个线程在工作。

阻塞线程的数量并不是很重要(只要它不是太大......),因为它们实际上不会消耗太多的 CPU 功率。

它与通常的阻塞模型不同,因为您隔离了不需要太多资源的阻塞操作。剩下的是在您拥有的工作线程之间共享剩余的事件驱动操作。

于 2014-03-14T18:34:03.527 回答
0

如前所述,您应该使用连接池,但是如果您对数据库访问而不是专门的 JDBC 感兴趣,则可以查看异步数据库驱动程序,例如:

这些驱动依赖于 netty,所以它的所有 IO 操作都是非阻塞的,这意味着你不需要工作线程池。更少的线程意味着操作系统级别的上下文切换更少,从而带来更好的性能。

遗憾的是,这些驱动程序并不多(我只知道 MySQL 和 PostgreSQL),所以如果你被迫使用其他 RDBMS,你可能会不走运。

于 2016-07-22T08:11:14.767 回答
0

正如其他人所建议的那样,请查看 mysql 和 postgres 的异步驱动程序,它们都有专门为 vert.x 制作的客户端。这两个数据库涵盖了 RDMS 的大多数用例。

另一个非阻塞选项是 MongoDB,它有一个定制的非阻塞 vert.x 客户端。效果很好,但当然不是 SQL。

于 2016-07-25T02:39:12.740 回答