Nodejs - 可以在线程池大小为 4 的同时运行的最大线程是多少?

Bha*_*vin 4 multithreading event-loop threadpool node.js

要求是每秒1000个并发请求和每个请求的数据库查询等IO操作。由于 nodejs 在事件循环上工作,它将 IO 操作分配给线程池,但线程池默认大小为 4,因此同时最多 4 个线程(IO 操作)可以工作,其余必须在队列中等待。一旦任何线程完成执行,它们就可以进行处理。

查询 1 - 我们可以根据需要将线程池大小增加到 N 数,它会提高性能还是会降低性能?

查询 2 - 我们如何在 nodejs 中实现上述要求?

查询 3 - Nodejs 是此要求或其他建议(例如 golang)的空闲选择

sle*_*man 5

node.js 上的网络 I/O 操作在主线程上运行。

是的,除了主线程之外,node.js 还会产生四个线程,但它们都没有用于网络 I/O,例如数据库操作。线程是:

  1. DNS 解析器(因为大多数操作系统仅为此提供同步 API)

  2. 文件系统 API(因为异步跨平台这样做很麻烦)

  3. 加密(因为这使用 CPU)

  4. Zlib(zip 压缩)

除非您自己生成,否则其他所有内容都不要使用线程worker_threads。有关更多信息,请参阅节点自己的文档:https : //nodejs.org/en/docs/guides/dont-block-the-event-loop/。不要依赖不是来自 node.js 项目本身的信息,例如 youtube 或媒体文章,这些文章说节点 I/O 使用线程池 - 他们不知道他们在说什么。

增加线程池大小不会对网络 I/O 做任何事情,因为 node.js 根本没有任何代码来使网络 I/O 利用额外的线程。如果您想将负载分散到多个处理器上,您可以使用集群。您可以编写自己的集群代码或使用pm2等进程管理器的集群模式将连接传递给您的进程。

如果 node 只使用一个线程,它怎么能声称是高性能的!

大多数非系统程序员没有意识到的是,等待 I/O 的 CPU 时间恰好为零。通过生成线程来实现这意味着您要分配大量的 RAM,并且大多数情况下所有这些线程都使用CPU 时间(想象一下生成 1024 个线程,每个线程根本不使用 CPU)。当这些线程(或者在 node.js 的情况下是主线程)正在等待来自数据库的 1000 个回复时,操作系统将这些请求排入一系列数据包并将它们发送到您的网卡,后者又将它们发送到数据库一次一点- 是的,其核心的 I/O 不是并行的(除非您在多个网卡上使用中继)。所以大部分繁重的工作都是通过以太网完成的,而您的进程被操作系统暂停(等待)。

node.js 所做的是,当请求正在等待时,它会发出另一个请求。这就是非阻塞的意思。在处理所有其他请求之前,节点不会等待请求完成。这意味着默认情况下,您在 node.js 中发出的所有请求都是并发的——它们不会等待其他请求完成。

在请求完成端,从服务器收到的任何响应都会触发节点搜索事件队列(实际上这只是一个集合,因为队列中的任何项目都可以随时完成)并找到相应的回调来调用。执行回调确实需要 CPU 时间,但不会等待网络请求。

这就是像 node.js 这样的系统可以与多线程系统竞争的原因。事实上,在某些情况下可以胜过多线程系统,因为在同一个线程上执行它意味着您不需要锁(互斥锁或信号量)并且您避免了上下文切换的成本(当操作系统将一个线程置于睡眠状态时,复制所有线程)寄存器值到 RAM,然后唤醒另一个线程,从 RAM 中为新进程复制寄存器值)。

  • @mohdule 100% CPU 负载很奇怪。您的节点脚本应使用接近 0% 的 CPU。即使负载很重,对于普通服务器来说,它也不会超过 10%,除非您正在执行媒体转码或压缩/解压缩大型 (100MB+) 文件之类的操作。如果 CPU 使用率停留在 100%,则意味着代码中有无限循环(或长时间运行的循环) (2认同)
  • @mohdule 这是我的一台实时服务器负载的屏幕截图。该服务器运行 POS 系统以及超市的在线订购和履行系统。它运行两个 Java 服务和一个 Node 服务。如您所见,当前 CPU 负载约为 1% 到 2%。我拍这张照片时并不是高峰时间,但结账处有顾客——https://static.rcgroups.net/forums/attachments/2/6/7/7/4/4/a14861913-103-Screenshot% 20at%202021-04-13%2010-36-26.png。 (2认同)