为啥 Node.js 是单线程的? [关闭]

Posted

技术标签:

【中文标题】为啥 Node.js 是单线程的? [关闭]【英文标题】:Why is Node.js single threaded? [closed]为什么 Node.js 是单线程的? [关闭] 【发布时间】:2013-07-31 08:18:09 【问题描述】:

在基于 php(或 Java/ASP.NET/Ruby)的网络服务器中,每个客户端请求都在一个新线程上实例化。但是在 Node.js 中,所有客户端都在同一个线程上运行(它们甚至可以共享相同的变量!)我知道 I/O 操作是基于事件的,因此它们不会阻塞主线程循环。

我不明白为什么 Node 的作者选择它是单线程的?它使事情变得困难。例如,我无法运行 CPU 密集型函数,因为它阻塞了主线程(并且新的客户端请求被阻塞),所以我需要生成一个进程(这意味着我需要创建一个单独的 javascript 文件并在其上执行另一个节点进程它)。但是,在 PHP 中,CPU 密集型任务不会阻塞其他客户端,因为正如我所提到的,每个客户端都在不同的线程上。与多线程 Web 服务器相比,它有哪些优势?

注意:我已经使用集群来解决这个问题,但它并不漂亮。

【问题讨论】:

我最近看了一个很好的视频(29 分钟),解释了 Node.js 背后的一些理论。我什至认为这家伙谈到了 CPU 密集型任务以及如何处理它们:youtube.com/watch?v=L0pjVcIsU6A 你可能知道这一点,但要清楚 Node.js 不是单线程的。您的 JavaScript 代码运行单线程,但 IO 操作和插件可以执行的其他操作在线程池之外运行。 Node.js 为您提供了多线程的许多好处,而无需处理多线程代码。此外,Node.js 的贡献者并没有选择 JavaScript 的单线程特性,JavaScript 的作者选择了。我想不出一种 JS 可以在多线程上下文中工作的方式,但即使有,V8 也不是 Node.js 用作其 JavaScript 引擎的那种方式编写的。 PHP 比 JavaScript 更单线程。您可能正在考虑像 FastCGI 或 mod_php 这样的服务器模块。因此,您实际上是在将 Node.js 与 Apache、nginx 或 IIS 进行比较,而不是与 PHP、Java 或 Ruby 进行比较。 节点不是单线程的。这是一个流行的误解。即使是简单的node -e 'setTimeout(()=>,1000);' & ps -T h $! | wc -l; kill $! 也会在我的系统上显示五个线程。主 事件循环 是单线程的(如果不是这样就没有多大意义),但 Node 是多线程的,如果你愿意,你可以编写多线程的单进程应用程序.我很想写一个关于它的全面答案,但有些人决定关闭你的问题,所以我不能。我正在投票重新开放它。如果它获得更多选票并重新开放,请在评论中提及我。 @rsp 感谢您的评论,但我的意思是在主线程中与 i/o 无关。如果您正在执行与 cpu 相关的操作,例如执行某些操作的大 for 循环,则服务器将停止处理连接。意思是,服务器当时不可用。所以我们只能使用像集群这样的黑客来做一些如此简单的事情,而不是像大多数服务器那样固有地线程化每个连接。 jxcore.com 试图解决这个问题,但后来它使用了特殊/修改过的节点插件,这基本上使它对我来说无法使用。 【参考方案1】:

Node.js 是作为异步处理的实验显式创建的。其理论是,在单个线程上进行异步处理可以在典型的 Web 负载下提供比典型的基于线程的实现更高的性能和可扩展性。

你知道吗?在我看来,这个理论已经得到证实。与 Apache 或 IIS 或其他基于线程的服务器相比,不执行 CPU 密集型工作的 node.js 应用可以运行数千个以上的并发连接。

单线程、异步特性确实使事情变得复杂。但是你真的认为它比线程更复杂吗?一个比赛条件可能会毁了你整个月!或者由于某处的某些设置而清空您的线程池,并观察您的响应时间缓慢到爬行!更不用说死锁、优先级倒置以及多线程带来的所有其他问题。

最后,我不认为这是普遍的好坏;它是不同的,有时它更好,有时它不是。为工作使用正确的工具。

【讨论】:

但是网络服务器通常会做很多 CPU 密集型的工作,而不仅仅是数据库获取。我们需要处理我们获取的内容,并且在将其提供给客户端之前经常执行大量业务逻辑。 所以只产生工人,好吧!这就是 Node.js 的全部内容。重的东西可以在另一个进程中运行,你处理它的结果是一个轻量级的回调。 问题在于每个工作人员都在运行一个操作系统级别的进程。您将使用“ps”命令看到它们。所以这可能意味着机器上同时运行数千个进程 - 这太疯狂了! @foreyez,您不需要每个用户的进程。您可以选择如何分配负载。此外,并不是每个人都在做大量 CPU 密集型的工作。 Node 是工作的工具……也许不是你的工作,而是多种工作。 实际上,我希望@foreyez 支持“网络服务器通常用于大量(原文如此)cpu 密集型内容”的说法。根据我的经验,他们没有。或者也许我对“cpu 密集型”的定义与他的不同。将产品数据转换为 UI 不是 CPU 密集型的,计算订单等也不是。大多数网络都是交易性的。 CPU 密集型的东西是转换视频,转换图像格式等。其中大部分是由于文件 i/o,实际上,node 做得很好。并且可以轻松卸载到专门用于转换的另一个进程。【参考方案2】:

服务器的“每个请求一个线程”模型的问题在于,与事件循环线程模型相比,它们不能很好地适应多种场景。

通常,在 I/O 密集型场景中,请求花费大部分时间等待 I/O 完成。在此期间,在“一个请求一个线程”模型中,链接到线程的资源(例如内存)是未使用的,内存是限制因素。在事件循环模型中,循环线程选择下一个事件(I/O 完成)来处理。所以线程总是很忙(当然如果你编程正确的话)。

所有新事物的事件循环模型看起来都很闪亮,所有问题的解决方案,但使用哪种模型取决于您需要处理的场景。如果您有密集型 I/O 场景(如代理),则事件基础模型将成为主导,而并发进程数量较少的 CPU 密集型场景最适合基于线程的模型。

在现实世界中,大多数场景都处于中间位置。您需要平衡对可扩展性的真正需求与开发复杂性,以找到正确的架构(例如,有一个事件库前端,将 CPU 密集型任务委托给后端。前端将使用很少的资源等待任务结果。)与任何分布式系统一样,它需要一些努力才能使其工作。

如果您正在寻找能够不费吹灰之力地适应任何场景的灵丹妙药,那么您最终会被子弹击中。

【讨论】:

Node.js 由于缺乏 v8 多线程支持,因此仅限于仅事件处理。好吧,javascript 语言本身缺乏所需的功能,因此任何实现最终都会变得棘手。在我看来,这是 Node.js 的罪魁祸首。在其他语言中,您可以选择您想要的。或者两种模型的混合体,比如 java NIO。 @Kazaag,现代网络服务器维护一个线程池。他们不只是在每个页面加载时愚蠢地产生一个新线程。这些是较旧的网络服务器。 @Pacerier 我从来没有说过会产生一个新线程,但是每个线程都分配给一个请求,直到请求完成。 @Kazaag “每个线程分配给一个请求,直到请求完成”绝对不是一般规则。 IE。在 .Net(包括处理 HTTP 请求)中,可以而且应该使用异步(基于任务)编程,这将在等待 I/O 和其他异步操作完成时释放线程。这也适用于高级编程,即 MVC/API 控制器。所以实际上可能有 20 个 HTTP 请求待处理,但只有一个活动线程。【参考方案3】:

长话短说,节点从 V8 中提取,内部是单线程的。有一些方法可以解决 CPU 密集型任务的限制。

在某一时刻 (0.7),作者试图引入隔离作为实现多线程计算的一种方式,但最终被删除:https://groups.google.com/forum/#!msg/nodejs/zLzuo292hX0/F7gqfUiKi2sJ

【讨论】:

你有更多关于这个“隔离”的信息吗? V8 不是单线程的

以上是关于为啥 Node.js 是单线程的? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Node.js的事件处理机制

nodejs是单线程还是多线程

Node.js 单线程模型

nodejs如何开启多线程

Node.js机制及原理理解初步

为啥大多数 UI 框架都是单线程的?