形象理解Node.js的三大特点:单线程、非阻塞I/O,事件驱动
Node.js是什么?
Node.js
是一个用C++
开发的基于 Chrome V8
引擎的 Javascript
运行环境( 即Javascript 语言解释器)。
大神ryan dahl编写Node.js
时想实现的是非阻塞式 I/O、事件驱动。因为他认为一个高性能服务器应该是满足“事件驱动,非阻塞 I/O”模型的。
Node.js带来了什么?
- 传统上 ,
Web
开发者用Javascript
写前端,但是写服务器端用另外一种语言:Ruby/Java/PHP
等。
但是Node.js
出现之后,Javascript
前后端通吃了。
如果去网上搜Node.js
的资料,很多都是用Node.js
去写服务器代码的。 - 以前
Javascript
只能运行在浏览器中,Node.js
出现之后,不管是服务器上,还是我们自己的的笔记本上,只要安装了Node.js
就可以运行Javascript
代码了。
前言:两个故事
为了更好地理解Node.js的三大特点,先给大家讲一大一小两个餐馆的故事。
-
高级餐厅(传统的服务器语言)
我们到一个比较高级的餐厅吃饭,服务员是一对一服务(每个用户都是一个线程),从我们坐下开始,服务员就把菜单给你,然后在旁边等你点菜(等待 I/O 操作),当你看完菜单,把要点的菜告诉服务员( I/O 操作结束后线程继续执行)。在你看菜单的过程中,服务员其实是被闲置的,如果你一直看,他就会一直等,直到你点完( I/O 操作结束)。这就是阻塞式 I/O。 -
小餐馆(Node.js)
一个规模比较小的餐馆,雇不起大量的服务员,只能雇佣一个服务员。当有顾客来时,服务员把菜单送过去,顾客开始看菜单( I/O 操作),这个时候,服务员是被释放了的,他不用等待顾客看菜单,服务员说:“您先看着菜单,点好了叫我”(回调函数)。这个时候这个服务员就可以抽身去服务其他的顾客。用这种模式的话,一个服务员就可以服务多位顾客,而且不需要等待 I/O ,只需要随时监听就行了,顾客点完后会主动叫服务员(执行回调函数)。
Node.js的三大特点
1. 单线程与多线程
高级餐厅是多线程:给每一个用户分配一个服务员(多个服务员,多线程)
小餐馆是单线程:所有用户共享一个服务员(一个服务员,单线程)
2. 阻塞 I/O与非阻塞 I/O
高级餐厅是阻塞 I/O:服务员(线程)在旁边等你点菜(等待 I/O 操作),直到你点完菜( I/O 操作)之后,线程才继续执行。
小餐馆是非阻塞 I/O(异步 I/O):服务员(线程)不等待你点菜(不等待 I/O 操作)而抽身去服务其他的顾客,只需要随时监听,顾客点完后主动叫服务员(执行回调函数)。
3. 事件驱动
但是,还有一个问题就是,如果有多个顾客都在叫小餐馆的一个服务员,该如何响应?肯定要有一定的规则,这就涉及到了 Node.js的事件驱动。
在一些应用场景中,我们希望程序是被“事件”触发运行的,并且程序在感知到不同的“事件”后能够产生不同的响应动作(比如小餐馆的用户点菜完成之后,需要召唤服务员收回点菜单交给后厨),此时就需要应用程序能够实时“感知”其所关心的事件,并在事件发生后执行相应的操作。
在解决上述问题时,应用程序是由“事件”驱动运行的,我们可以将这种编程模型称为事件驱动模型。
事件驱动模型
事件驱动模型大体思路如下:
- 有一个事件(消息)队列;
- 当有事件发生时,往这个队列中增加一个事件(消息);
- 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数;
- 事件(消息)一般都各自保存各自的处理函数指针,这样,每个消息都有独立的处理函数;
事件驱动编程是一种编程范式,程序的执行流由外部事件来决定。它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。
在事件驱动的程序中,各个任务交错执行,但仍然在一个单独的线程控制中。当处理I/O或者其他昂贵的操作时,注册一个回调到事件循环中,然后当I/O操作完成时继续执行。回调描述了该如何处理某个事件。事件循环轮询所有的事件,当事件到来时将它们分配给等待处理事件的回调函数。这种方式让程序尽可能的得以执行而不需要用到额外的线程。
当我们面对如下的环境时,事件驱动模型通常是一个好的选择:
程序中有许多任务,而且…
任务之间高度独立(因此它们不需要互相通信,或者等待彼此)而且…
在等待事件到来时,某些任务会阻塞。
当应用程序需要在任务间共享可变的数据时,这也是一个不错的选择,因为这里不需要采用同步处理。
网络应用程序通常都有上述这些特点,这使得它们能够很好的契合事件驱动编程模型。
总结
- 传统的服务器语言大多是多线程、阻塞式 I/O:对于传统的服务器语言,在与用户建立连接时,每一个连接(每一个用户)都是一个线程。 当有十万个用户连接时,服务器上就会有十万个线程。阻塞式 I/O 是指,当一个线程在执行 I/O 操作时,这个线程会阻塞,等待 I/O 操作完成后继续执行。
而Node.js是单线程、非阻塞I/O,这是它与众不同的地方,其最大的优势就是性能强:同样的服务器性能使用Node.js可以比传统的服务器语言多容纳一百倍的用户(对于不同的任务有不同的差别, I/O 操作越多,node优势越明显,如果都是 CPU 计算任务,那他俩几乎没有区别(上面的例子中,忽略顾客的看菜单时间)。 - 单线程、非阻塞式 I/O 的优势就是性能强,一个人服务员就可以解决大量顾客。但是他的缺点也很明显,比如有一桌顾客和服务员又吵架了(线程崩了!),那这些顾客就都完了,因为所有人都在等这一个服务员。也就是说,如果线程崩掉了,那与这个服务器连接的所有用户都会崩溃(单点故障)。
- 单线程、非阻塞式 I/O的
Node.js
的工作方式是事件驱动。
参考链接
- https://www.jianshu.com/p/22c27f827304
- https://blog.csdn.net/cbmljs/article/details/86574353
- https://blog.csdn.net/sinat_36817189/article/details/106205029
后记(npm介绍)
Node.js
引发了前后端开发的爆发,尤其是前端。 JS 开发者众多,所以贡献开源代码的人就非常多,所有这些凝结成了 npm
这个世界上最大的软件包仓库。
npm
是 Node Package Manager
的缩写,意思是 Node 的包管理系统。在这里,我们要实现各种功能几乎都能找到现成的别人写好的包,直接拿了用就好了。
很多 npm
包都对应一个 Github
项目,但是如果只有代码,那么使用起来还不是特别方便。而当系统上安装好了 Node.js
之后,就会配套安装一个命令,叫做 npm
。
npm install moment
然后执行 npm install moment
就可以把 moment
这个包从 npm
的软件包仓库中下载下来,并安装到本地了。而 npm 的软件包仓库中,有数以万计的 moment 这样的包。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/119072.html