知识总结与整理:Node.js专题二(Node主要特性)

如果我们平常有浏览有关Node.js的文章,估计我们都会听到最多关于Node.js是异步非阻塞I/O,单线程事件机制。本章节主要去深入探讨这几种特性(PS:本文是对所学知识的学习和总结,可能存在理解错误。请带着怀疑的眼光,同时如果有错误希望能指出。)

章节二.png

一、Node.js的异步I/O,非阻塞I/O

首先我们先来理解几个概念:阻塞IO(blocking I/O)非阻塞IO(non-blocking I/O)同步IO(synchronous I/O)异步IO(synchronous I/O)

问题:这里肯定有人想问,异步I/O和非阻塞I/O不是一回事吗??

答案:异步I/O和非阻塞I/O根本不是同一回事,曾经笔者一直天真的以为非阻塞I/O就是异步I/O T_T(直到看见朴灵大神的深入浅出Node.js)。

1.现在我们来了解什么是异步I/O,什么是同步I/O?

这里转自有趣的知乎er
老张爱喝茶,废话不说,煮开水。出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
1:老张把水壶放到火上,立等水开。(同步阻塞)老张觉得自己有点傻
2: 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
3:老张把响水壶放到火上,立等水开。(异步阻塞)老张觉得这样傻等意义不大
4: 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)老张觉得自己聪明了。
所谓同步异步,只是对于水壶而言。普通水壶,同步;响水壶,异步。虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。
所谓阻塞非阻塞,仅仅对于老张而言。立等的老张,阻塞;看电视的老张,非阻塞。情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。
作者:愚抄
链接:https://www.zhihu.com/question/19732473/answer/23434554
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

二、单线程

在专题一的介绍,我们指导Node.js的runtime是V8,而V8设计是为了让Chrome浏览器对Javascript语言进行编译和解析的,另外有过JS经验的工程师都知道,JS的最大特点是单线程,而Node.js对V8的延用也是针对这一非常重要的特点。那么什么是单线程,单线程指的是,一个进程只能拥有一个线程,程序按顺序执行,只有等到前面的程序执行完毕,才能执行下一个!来看看Node对Http服务的模型,

node_http_model.png

Node.js单线程指的是主线程是单线程,由主线程按照编码顺序一步步执行,当主线程遇到阻塞的时候,后续的程序就会被卡住无法执行。说了这么多,不如来实践一下验真假:

实验.png

先将index.js的代码改成这样,然后打开浏览器,你会发现浏览器在10秒之后才做出反应,打出Hello Node.js

堆栈图.png

JavaScript是解析性语言,代码按照编码顺序一行一行被压进stack里面执行,执行完成后移除然后继续压下一行代码块进去执行。上面代码块的堆栈图,当主线程接受了request后,程序被压进同步执行的sleep执行块(我们假设这里就是程序的业务处理),如果在这10s内有第二个request进来就会被压进stack里面等待10s执行完成后再进一步处理下一个请求,后面的请求都会被挂起等待前面的同步执行完成后再执行,所以这也说明Node.js单线程的执行模型,因为这样的特性,我们的页面不能有耗时很长的同步处理程序阻塞了程序的后续执行,而对于耗时过长的程序应该采用异步执行,这里也就是Node.js的第二个特性,异步。

三、异步

我们平时说的Node.js是异步的,那么具体是指那部分异步,而答案是主线程的异步处理函数队列+多线程异步I/O

1.主线程的异步处理函数队列

上面那句话看上去是不是有点抽象难懂,现在来进行解释,所谓主线程异步处理函数队列是指主线程的主要执行空间除了stack(执行栈)head(产生堆)外,还会callback queue(回调函数队列),而callback queue是存放了异步处理的回调函数,当一个异步I/O处理完,就会向callback queue存放一个回调函数,当stack里面的程序执行完,主线程就会从callback queue取出已经存放好的回调函数去执行,而我们平时最常见的异步,除了事件外,还有timer,例如setTimeout,不如我们举一个栗子~

let sleep = (time)=>{
    let exit = Date.now+time*1000;
    while(Date.now()<exit){};
    console.log('end sleep')
    return
}

let main = ()=>{
    setTimeout(()=>{
         console.log('setTimeout run');
    },0)
    sleep(5);
    console.log('after sleep');
}

main()

执行输出:
end sleep
after sleep
undefined(由于每个函数执行完都会自行return,如果没指定,就会输出undefined,这个是main执行完return出来的)
setTimeout run

下面是代码块的主线程堆栈执行:

异步.png

看上图,主线程将main函数压进stack里面一行行解析执行,首先遇到setTimeout方法,因为setTimeout是一个异步处理函数,这里会setTimeout(callback,timeout),里面的callback函数移进callback queue里面,同时会把自己从主线程的stack里面移除,继续压进后面的执行代码来解析执行,这里继续压进sleep沉睡5s,接下来执行console,等到这里的同步代码执行完成后这个时候就会从callback queue里面取回调函数一个个执行。(题外话:就算setTimeout里面的timeout设置了是0,都是要等待执行块里面的同步代码执行完成后再去执行callback queue里面的代码)这就是异步里面的其一:主线程异步函数处理队列。(PS,setTimeout的回调函数的执行时间不是当前队列,而是下一个执行队列,即是是设置为,也最多是下一次执行队列第一个执行,详情阮一峰JS运行机制)

2.多线程异步I/O

这里可能有人会有疑问,买卖皮喔!你不是说Node.js是单线程吗,你这不是自己打脸吗?我想说,这里其实是没有冲突的,Node.js每个进程里面只有一个主线程来处理程序。因此,主线程是单线程,而主线程之外调用的I/O处理是通过一个叫做线程池的结构来管理的,所以I/O的处理是多线程的,而主线程和I/O线程池则通过上面刚刚讲述的主线程的异步处理函数队列来协作。(PSNode.js只对文件系统以及DNS实现了多线程I/O封装,网络I/O还是采用单线程形式)如图:

多线程.png

上图在主线程中,当遇到需要处理的I/O时,就将I/O的处理放在I/O线程池中管理,而主线程继续执行,当I/O线程池中有I/O完成了,就会想callback queue注册回调函数等待主线程执行,而Node.js的高性能也是得益于其将阻塞的I/O异步化,使得不影响主逻辑的执行。

四、事件驱动

文章至此,我们先进行总结,Node.js至此我们简介了两个主要特性,单线程异步,每个Node程序只会在主线程中执行程序代码,在执行过程中将阻塞的I/O操作异步化,将放至I/O线程池中进行管理,当线程池中有I/O操作完成,就会向callback queue注册回调函数,等待同步逻辑执行完成后再通过callback queue里面取出回调函数压进stack里面执行,好了,而事件驱动的作用就是取出回调函数。事件驱动又叫事件循环,是指主线程从主线程的异步处理函数队列里面不停循环的读取事件,驱动了所有的异步回调函数的执行。详情Node事件轮询

事件机制.png

至此整个Node.js的异步化逻辑可以不断循环的跑起来了,以上则是我们日常所言的Node.js的三大特性以及其原理。

参考资料:
Node事件轮询
JS运行机制
Node.js特性分析
非阻塞I/O和异步I/O的区别

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容