根据https://nodejs.org/api/cluster.html#cluster_cluster的说法,应该与计算机上的核心数并行运行相同数量的Node.js进程。这背后的假设是Node.js是单线程的。
但是,这是真的吗?确实JavaScript代码和事件循环在一个线程上运行,但Node也有一个工作线程池。此池中的默认线程数为4.那么为什么每个核心运行一个Node进程是有意义的呢?
This article对node.js的线程机制进行了扩展审核,值得一读。
简而言之,主要的观点是在plain node.js中,只有少数函数调用使用线程池(DNS和FS调用)。您的呼叫主要仅在事件循环上运行。因此,例如,如果您编写了一个Web应用程序,每个请求同步需要100毫秒,那么您将被绑定到10req / s。线程池不会涉及。增加多核系统的吞吐量就是使用其他核心。
然后是异步或回调函数。虽然它确实给你一种并行化的感觉,但真正发生的是它等待异步代码在后台完成,以便事件循环可以在另一个函数调用上工作。之后,回调代码仍然必须在事件循环中运行,因此所有编写的代码仍然只在一个事件循环中运行,因此无法利用多核系统的功能。
所述document明确指出Node是单线程的:
Node.js的单个实例在单个线程中运行。为了利用多核系统,用户有时会想要启动一个Node.js进程集群来处理负载。
这样Node节点就有一个线程,除非使用child_process
,cluster
,native native-ons或several built-in modules等使用libuv
treadpool的相应API创建新线程:
Node.js尽可能使用异步系统API,但如果它们不存在,libuv的线程池用于基于同步系统API创建异步节点API。使用线程池的Node.js API是:
除文件监视器API和明确同步的API之外的所有fs API
crypto.pbkdf2()
crypto.randomBytes(),除非在没有回调的情况下使用它
crypto.randomFill()
dns.lookup()
除了那些明确同步的API之外的所有zlib API
单个线程使用1个CPU内核,为了最大限度地利用可用资源并利用多核CPU,应该有多个线程,核心数量用作经验法则。
如果集群进程占用100%的CPU,并且已知有其他线程或外部进程(数据库服务)可以通过集群进程争夺CPU核心,则可以减少集群进程的数量。