node.js服务器如何比基于线程的服务器更好

Node.js服务器适用于支持callback函数的基于事件的模型。 但是我不能理解它比线程等待系统IO的传统基于线程的服务器更好。 在基于线程的模型的情况下,当一个线程需要等待IO,它被抢占,所以不消耗CPU周期,因此不会造成等待时间。

Node.js如何提高等待时间?

线程是相对重的对象,其资源占用空间一直延伸到内核中。 当你在一个阻塞的系统调用或一个互斥或条件variables中驻留一个线程时,你正在绑定所有这些资源,但是什么都不做。 现在操作系统不得不寻找更多的资源,所以你的程序可以创build另一个线程…然后你也可以让它们闲置 不久之前,操作系统正在努力为您的程序清除更多的资源,以免浪费。

CPU时间只是他大局的一小部分。 🙂

当一个线程需要等待IO时,它将被抢占

事实上,它并没有被抢占。 抢占是完全不同的。 发生什么事是线程被阻塞。

对于基于事件的模型,会发生类似的事情 基于事件的解释器基本上是状态机。 只有状态机被抽象出来并且对用户不可见。 当某事正在等待某个事件时,它将控制传回给解释器。 当解释器没有其他东西要处理时,它自己等待I / O。 只有与传统的线程代码不同,解释器才会等待多个I / O。

在C级别发生的事情是解释器使用诸如select() ,poll(),epoll()和朋友(取决于所安装的操作系统和库)来做阻塞和等待I / O。

现在,为什么基于select() / poll()的机制通常performance更好? 实际上, “一般”取决于你的意思。 基于select()的服务器执行单个进程/线程中的所有代码。 最大的性能提升是它避免了上下文切换 – 每次操作系统将控制权从一个线程转移到另一个线程时,必须保存所有相关的寄存器,存储器映射,堆栈指针,FPU上下文等,以便另一个线程可以从停止的地方恢复执行。 这样做的开销可能相当大。

事实上,有一个历史性的例子,可能会有多大的开销。 早在二十一世纪初,有人开始对Web服务器进行基准testing。 令所有人感到意外的是, tclhttpd在服务静态文件方面胜过了Apache 。 现在,tcl不仅是一种解释型语言,但早在2000年,它就是一种非常缓慢的解释型语言,因为它没有独立的编译阶段(现在这样做)。 Tcl脚本是以stringforms直接解释的,比C慢了400 倍 .Apache显然是用C编写的,所以tclhttpd的速度是怎样的?

事实certificate, tclhttpd是基于事件的,只在单线程上运行,而Apache是multithreading的。 不断的线程切换开销给了tclhttpd足够的优势来比Apache执行更好。

当然,总是有一个妥协。 像tclhttpd或node.js这样的单线程服务器不能利用多个CPU。 早在二十一世纪初,多CPU并不常见。 这几天他们几乎是默认的。 更不用说大多数CPU也是超线程的(超线程增加了CPU的硬件,使上下文切换便宜)。

这些日子里最好的服务器已经从历史中吸取了教训,并且是两者的结合。 Apache2和Nginx使用的是存储池:它们是multithreading的,但每个线程不止一个连接。 这是两种方法的混合,但更复杂的pipe理。

请阅读以下文章,以获得有关此主题的更深入的讨论: C10K问题

简单的说:

在一个线程服务器中,不pipe你有多less个线程,总是可以有很multithreading等待IO。

在节点中,不pipe有多lessIO操作正在等待,你总是有事件循环准备好做下一件事情。

当有很多的线程,你会有很多的上下文切换 ,这将是昂贵的。 当使用node.js的Event循环时,你想要这个开销

上下文切换

上下文切换是存储和恢复CPU的状态(上下文)的计算过程,以便稍后可以从同一点恢复执行。

事件循环

在计算机科学中,事件循环,消息调度器,消息循环或消息泵是一种编程构造,它等待并分发程序中的事件或消息。

我认为你对上下文切换的线程和成本充满了神话。

发现自己的真相。