首页 > 解决方案 > Nodejs - 可以在线程池大小为四个的同时运行的最大线程是多少?

问题描述

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

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

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

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

标签: node.jsmultithreadingthreadpoolevent-loop

解决方案


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

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

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

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

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

  4. Zlib(压缩压缩)

除非您自己 spawn ,否则其他所有内容都不要使用线程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等进程管理器的集群模式将连接传递给您的进程。

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

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

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

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

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


推荐阅读