Node.js 异步原理

栏目: Node.js · 发布时间: 7年前

内容简介:Node.js 异步原理

写文章写得实在生无可恋,依旧看起了书——《深入浅出 Node.js》,觉得自己确实有错,之后如果有人问我 Node.js 入门怎么入门我可能还是会推荐他网上的教程,但是说到推荐书,这确实是一本很棒的书。

——安利完毕,之后进入正题。

在面试时可能真的会遇到这样的情况,面试官问:请问一下异步是怎么实现的。

之前在听小伙伴说到这个问题的时候一脸黑人问号,毕竟仿佛是一知半解,不得其意,今天总算可以好好聊一聊异步了,也算是一个章节的笔记。不过掌握的还不是很透彻,如果有错误请指出。

为什么会有异步

  1. 单线程同步模型系统资源利用率低下
  2. 多线程模型线程切换开销大,多线程编程中的同步问题让人头大

异步让单线程远离阻塞,同时规避了线程切换(恢复现场)的开销,让单一线程在执行 I/O 操作后立即进行其他操作。

异步 I/O 与非阻塞 I/O

尽管异步与非阻塞我们常常一起提及,异步也确实解决了非阻塞的问题,但是在计算机内核的角度,这并不是同一回事。

我们知道,阻塞 I/O 造成了 CPU 等待,浪费了系统资源,而非阻塞 I/O 会在执行完毕后立即返回,如果需要获得数据,需要再次读取。系统通过轮询来获取非阻塞 I/O 的结果,对 CPU 资源又存在浪费。

现在主要的轮询技术有: read / select / poll / epoll

其中 epoll 在进入轮询后没有检测到 I/O 事件将会休眠,直到事件发生,利用率较高,但仍然需要花费资源去等待与确认。

我们理想中的异步应该是可以在进行一次 I/O 之后不闲置 CPU,不去关心,直到完成之后执行回调。

现实中也确实有好几种异步方案,在 Node.js 和 Windows 下的 IOCP 中都使用线程池完成异步 I/O。Node.js 中利用 libuv 封装,来判断平台进行兼容。

Node.js 异步原理

事件循环

Node.js 中的异步 I/O 当然得提到大名鼎鼎的事件循环了,如果面试只面试到这里,相信每个人都能说出来:

事件循环就是执行一次循环(一个 Tick),就检测是否有事件未处理,如果有,就取出事件及相关回调函数,如果存在关联的回调函数,就执行它们,然后进入下一循环,如果没有,就退出进程。

事件循环就是一个典型的生产者消费者模型,由请求生产,事件循环消费,这个循环由 IOCP / 多线程创建。

首先我们引入请求对象的概念,JavaScript 层传入的参数和方法都被封装在请求对象中,当有可用线程时,我们就会调用对象底层对应的方法。

组装好请求对象,送入线程池等待执行,这就完成了我们的第一步。

执行结束后,将会将结果存储,并且调用方法通知 IOCP 将线程交还给线程池。

之后事件循环观察到执行完的请求,进行处理即可。

整个流程如图(摘自深入浅出 Node.js):

Node.js 异步原理

非 I/O 的异步 API

这部分介绍了一下 setTimeout , process.nextTick , setImmediate 的异同,可以从这里理解为什么 setTimeout 或者 setInterval 实现计划任务是个不靠谱的行为。

setTimeout 时创建的定时器会被插入到定时器观察者内部的一个红黑树中。每次 Tick 执行时,就会从该红黑树中迭代取出定时器对象,检测是否超时,如果超时就立即执行。

由此我们知道,如果两个定时 1ms 的任务,但是一个任务占用了 4 ms 的时间片,那么下一个任务就定然是不精准的。

行为图(摘自深入浅出 Node.js):

Node.js 异步原理

如果你需要立即执行一个任务,就应该使用 process.nextTick() 他可以规定和保证在下一个循环中执行。

此外,Node.js 还有一个 setImmediate() 方法,与 process.nextTick() 的区别是, process.nextTick 的回调函数保存在一个数组中,而 setImmediate 保存在链表中,在同一个 Tick 中会清空数组,但是只执行链表中的一项。此外, process.nextTick 在事件循环的检查中(idle 观察者)高于 setImmediate (check 观察者)。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java多线程编程实战指南(设计模式篇)

Java多线程编程实战指南(设计模式篇)

黄文海 / 电子工业出版社 / 2015-10 / 59.00

随着CPU 多核时代的到来,多线程编程在充分利用计算资源、提高软件服务质量方面扮演了越来越重要的角色。而 解决多线程编程中频繁出现的普遍问题可以借鉴设计模式所提供的现成解决方案。然而,多线程编程相关的设计模式书籍多采用C++作为描述语言,且书中所举的例子多与应用开发人员的实际工作相去甚远。《Java多线程编程实战指南(设计模式篇)》采用Java(JDK1.6)语言和UML 为描述语言,并结合作者多......一起来看看 《Java多线程编程实战指南(设计模式篇)》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具