理解Node.js的三大特点(单线程、非阻塞I/O,事件驱动)

导读:本篇文章讲解 理解Node.js的三大特点(单线程、非阻塞I/O,事件驱动),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com


Node.js是什么?

Node.js 是一个用C++开发的基于 Chrome V8 引擎的 Javascript 运行环境( 即Javascript 语言解释器)。

大神ryan dahl编写Node.js时想实现的是非阻塞式 I/O、事件驱动。因为他认为一个高性能服务器应该是满足“事件驱动,非阻塞 I/O”模型的。


Node.js带来了什么?

  1. 传统上 ,Web 开发者用 Javascript写前端,但是写服务器端用另外一种语言:Ruby/Java/PHP 等。
    但是 Node.js 出现之后,Javascript 前后端通吃了。
    如果去网上搜 Node.js 的资料,很多都是用 Node.js 去写服务器代码的。
  2. 以前Javascript只能运行在浏览器中,Node.js 出现之后,不管是服务器上,还是我们自己的的笔记本上,只要安装了 Node.js 就可以运行Javascript代码了。

前言:两个故事

为了更好地理解Node.js的三大特点,先给大家讲一大一小两个餐馆的故事。

  1. 高级餐厅(传统的服务器语言)
    我们到一个比较高级的餐厅吃饭,服务员是一对一服务(每个用户都是一个线程),从我们坐下开始,服务员就把菜单给你,然后在旁边等你点菜(等待 I/O 操作),当你看完菜单,把要点的菜告诉服务员( I/O 操作结束后线程继续执行)。在你看菜单的过程中,服务员其实是被闲置的,如果你一直看,他就会一直等,直到你点完( I/O 操作结束)。这就是阻塞式 I/O。

  2. 小餐馆(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的事件驱动。

在一些应用场景中,我们希望程序是被“事件”触发运行的,并且程序在感知到不同的“事件”后能够产生不同的响应动作(比如小餐馆的用户点菜完成之后,需要召唤服务员收回点菜单交给后厨),此时就需要应用程序能够实时“感知”其所关心的事件,并在事件发生后执行相应的操作。

在解决上述问题时,应用程序是由“事件”驱动运行的,我们可以将这种编程模型称为事件驱动模型。

事件驱动模型

事件驱动模型大体思路如下:

  1. 有一个事件(消息)队列;
  2. 当有事件发生时,往这个队列中增加一个事件(消息);
  3. 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数;
  4. 事件(消息)一般都各自保存各自的处理函数指针,这样,每个消息都有独立的处理函数;

事件驱动编程是一种编程范式,程序的执行流由外部事件来决定。它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。

在事件驱动的程序中,各个任务交错执行,但仍然在一个单独的线程控制中。当处理I/O或者其他昂贵的操作时,注册一个回调到事件循环中,然后当I/O操作完成时继续执行。回调描述了该如何处理某个事件。事件循环轮询所有的事件,当事件到来时将它们分配给等待处理事件的回调函数。这种方式让程序尽可能的得以执行而不需要用到额外的线程。

当我们面对如下的环境时,事件驱动模型通常是一个好的选择:
程序中有许多任务,而且…
任务之间高度独立(因此它们不需要互相通信,或者等待彼此)而且…
在等待事件到来时,某些任务会阻塞。
当应用程序需要在任务间共享可变的数据时,这也是一个不错的选择,因为这里不需要采用同步处理。

网络应用程序通常都有上述这些特点,这使得它们能够很好的契合事件驱动编程模型。


总结

  1. 传统的服务器语言大多是多线程、阻塞式 I/O:对于传统的服务器语言,在与用户建立连接时,每一个连接(每一个用户)都是一个线程。 当有十万个用户连接时,服务器上就会有十万个线程。阻塞式 I/O 是指,当一个线程在执行 I/O 操作时,这个线程会阻塞,等待 I/O 操作完成后继续执行。
    而Node.js是单线程、非阻塞I/O,这是它与众不同的地方,其最大的优势就是性能强:同样的服务器性能使用Node.js可以比传统的服务器语言多容纳一百倍的用户(对于不同的任务有不同的差别, I/O 操作越多,node优势越明显,如果都是 CPU 计算任务,那他俩几乎没有区别(上面的例子中,忽略顾客的看菜单时间)。
  2. 单线程、非阻塞式 I/O 的优势就是性能强,一个人服务员就可以解决大量顾客。但是他的缺点也很明显,比如有一桌顾客和服务员又吵架了(线程崩了!),那这些顾客就都完了,因为所有人都在等这一个服务员。也就是说,如果线程崩掉了,那与这个服务器连接的所有用户都会崩溃(单点故障)
  3. 单线程、非阻塞式 I/O的Node.js的工作方式是事件驱动。

参考链接

  1. https://www.jianshu.com/p/22c27f827304
  2. https://blog.csdn.net/cbmljs/article/details/86574353
  3. https://blog.csdn.net/sinat_36817189/article/details/106205029

后记(npm介绍)

Node.js 引发了前后端开发的爆发,尤其是前端。 JS 开发者众多,所以贡献开源代码的人就非常多,所有这些凝结成了 npm 这个世界上最大的软件包仓库。

npmNode Package Manager 的缩写,意思是 Node 的包管理系统。在这里,我们要实现各种功能几乎都能找到现成的别人写好的包,直接拿了用就好了。

很多 npm 包都对应一个 Github 项目,但是如果只有代码,那么使用起来还不是特别方便。而当系统上安装好了 Node.js 之后,就会配套安装一个命令,叫做 npm

npm install moment

然后执行 npm install moment 就可以把 moment 这个包从 npm 的软件包仓库中下载下来,并安装到本地了。而 npm 的软件包仓库中,有数以万计的 moment 这样的包。

参考:https://zhuanlan.zhihu.com/p/47822968

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/119072.html

(0)
seven_的头像seven_bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!