283

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

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

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

4

3 回答 3

326

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

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

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

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

于 2013-07-31T00:36:13.863 回答
70

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

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

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

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

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

于 2013-07-31T08:27:47.007 回答
30

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

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

于 2013-07-31T00:45:07.113 回答