深入浅出NodeJS——异步I/O
底层操作系统,异步通过信号量、消息等方式有着广泛的应用。
PHP语言从头到尾都是以同步堵塞方式执行,利于程序猿顺序编写业务逻辑。
异步I/O、事件驱动、单线程构成Node的基调。
why异步I/O
(1)、用户体验
在Web2.0中Ajax广泛应用异步刷新机制能够更好的提高用户体验,消除UI堵塞。后端相同採用异步I/O能够有效较少同一时候请求多个资源的效应时间其为max(M,N)。
(2)、资源分配
多任务主流方式:
a. 单线程异步I/O
b. 多线程并行
多线程的代价在于创建线程和运行期线程上下午切换的开销较大。在复杂场景中,多线程常常面临锁、状态同步的问题。但多线程能够更有效的利用多核CPU,提高利用率。
NodeJS利用单线程远离多线程死锁、状态同步等问题;利用异步I/O,让单线程远离堵塞,以更好利用CPU。
为了弥补单线程无法利用多核CPU特点,Node採用类似Web Workers的子进程。
异步I/O
操作系统内核对于I/O仅仅有两种方式:堵塞和非堵塞
堵塞I/O一个特点是调用之后一定要等到系统内核层面完毕全部操作后,调用才结束。其造成CPU等待I/O,浪费时间和资源,CPU利用不充分。
非堵塞I/O不同之处在于调用之后会马上返回。其问题在于为了获取完整的数据,应用程序须要反复调用I/O操作来确认是否完毕,这样的反复调用判定是否完毕的技术叫做轮询
堵塞I/O会造成CPU等待浪费、非堵塞I/O须要轮询确认数据是否全然获取,让CPU处理状态推断,也会浪费CPU。轮询技术主要有下面几种:
(1) read。最原始效率最低的一种,反复调用来检查I/O的状态来完毕完整的数据读取。
(2) select。在read上改进,通过对文件描写叙述符上的事件状态进行推断。有个限制是因为採用1024长度的数组存储状态,最多能够同一时候检查1024个文件描写叙述符。
(3) poll。採用链表的方式避免数组长度的限制,其次能避免不须要的检查。但文件较多的时候,性能还是十分低下。
(4) epoll。linux下效率最高的I/O事件通知机制,在进行轮询的时候假设没有检查到I/O事件,将会进行休眠,直到事件发生将其唤醒。真实利用事件通知、运行回调的方式、而不是遍历查询。kequeue和epoll类似应用在FreeBSD下。
理想非堵塞异步I/O
多线程模拟理想非堵塞异步I/O,通过部分线程运行堵塞I/O或非堵塞I/O加轮询技术完毕数据获取,让一个线程进行计算处理,通过线程之间的通信将I/O得到的数据进行传递。
glibc的AIO是典型的线程池模拟异步I/O,然而其存在一些难以忍受缺陷,不推荐。
libio是由libev的作者又一次实现的一个异步I/O库,实质仍然是採用线程池与堵塞I/O模拟异步I/O。
IOCP是windows平台的异步I/O方案,提供理想的异步I/O:调用异步方法、等到I/O完毕后通知、运行回调、用户无需考虑轮询。其内部仍然是採用线程池原理,只是是线程池由系统内核管理。
Node提供libuv作为抽象封装层,兼容windows平台和*nix平台。
Node是单线程,这里的单线程仅仅是指JavaScript运行在单线程中。在Node中,不管是windows或*nix平台,内部完毕I/O任务另有线程池,仅仅是对用户透明罢了。Node自身事实上是多线程,仅仅是I/O线程使用CPU较少,除了用户代码无法并行运行,全部的I/O则是并行运行。
Node的异步I/O
Node运行模型—事件循环
在进程启动的时候Node会创建一个类似while(true)的循环,每次运行一个循环体的过程称为Tick。每一个Tick过程就是查看是否有事件待处理,若有则取出事件及其相关的回调函数,若存在关联的回调函数,则运行。
观察者
每一个事件循环中有一个或多个观察者,推断是否有事件待处理的过程就是向这些观察者询问是否有要处理的事件。
事件循环是一个典型的生产者/消费者模型。异步I/O、网络请求等是事件的生产者、源源不断为Node提供不同类型的事件、这些事件被传递到观察者那里,事件循环从观察者那里取出事件并处理。在Windows下,这个循环基于IOCP创建,而在*nix则基于多线程创建。
请求对象
从JavaScript发起调用到内核运行完毕I/O操作的过渡过程中,存在一个中间产物称为请求对象。
事件循环、观察者、请求对象和I/O线程池共同构成Node异步I/O模型的基本要素。
非I/O的异步API
setTimeout()和setInterval()分别用于单次和多次运行任务,其创建的定时器会被插入到定时器观察者内部的一个红黑树中。每次Tick运行时,会从该红黑树中迭代取出定时器对象,检查是否超过定时时间,若超过则形成一个事件,其回调函数马上运行。
定时器的问题在于,它并不是精确的,虽然事件循环十分快,但有可能某次Tick运行时间比較长。
process.nextTick()将回调函数放入到队列中,在下一轮Tick时取出运行,能够达到setTimeout(fn,0)的效果,因为不须要动用红黑树,效率更高时间复杂度为O(1)。
setImmediate()也是将回调函数延迟运行,process.nextTick()中的回调函数运行的优先级要高于setImmediate()。因为事件循环对观察者的检查是有先后顺序的,process.nextTick()属于idle观察者,setImmediate()属于check观察者,优先级例如以下idle观察者>I/O观察者>check观察者
process.nextTick()的回调函数保存在数组中,每次Tick会将数组中的回调函数所有运行;setImmediate()的回调函数保存在链表中,每次Tick仅仅运行链表中的一个回调函数。
深入浅出NodeJS——异步I/O的更多相关文章
- 深入浅出Nodejs读书笔记
深入浅出Nodejs读书笔记 转:http://tw93.github.io/2015-03-01/shen-ru-qian-chu-nodejs-reading-mind-map.html cate ...
- Node.js之路【第三篇】NodeJS异步实现
NodeJS异步实现 Node.js异步编程的直接体现就是回调,它依托于回调来实现,但不能说使用了回调他就是异步了 回调函数在完成任务后就会被调用,Node使用了大量的回调函数,Node所有的API都 ...
- Nodejs异步异常处理domain
前言 程序开发中,最麻烦的事情之一就是异常处理:对于Nodejs程序开发,最麻烦的事情莫过于异步异常处理. 以MVC的多层架构设计角度,异常总是要一层一层向上抛出,最后在客户端出打印错误.但是,Nod ...
- NodeJS异步I/O解析
在现在的项目开发中,任何一个大型项目绝对不是简简单单的采用一个种语言和一种框架,因为每种语言和框架各有优势,与其死守一个,不与取各家之所长,依次得到一个高性能.搞扩展的产品. 对于一个.NET开发者, ...
- 《深入浅出NodeJS》mindmap
接触NodeJS有快两年了,但因为和我的工作内容关系不大,所以一直没有系统的学习.最近终于有空能系统地了解学习一下这门技术,于是买了一本朴灵老师的<深入浅出NodeJS>仔细研读.这本书内 ...
- 《深入浅出Nodejs》笔记——模块机制(1)
前言 这是我读<深入浅出Nodejs>的笔记,真是希望我的机械键盘快点到啊,累死我了. CommonJS规范 主要分为模块引用.模块定义.模块标识三个部分. 模块引用 上下文提供requi ...
- 【读书笔记】《深入浅出nodejs》第四章 异步编程
1. 异步编程的基础 -- 函数式编程 (1)高阶函数 -- 是可以把函数作为参数,或是将函数作为返回值的函数. (2)偏函数用法 -- 创建一个调用另外一个部分 -- 参数或变量已经预置的函数 -- ...
- 【读书笔记】《深入浅出nodejs》第三章 异步I/O
1. 为什么要异步I/O (1)用户体验上: 并发的优势: M+N+... -> max(M,N,...) --> 使后端能够快速的响应资源 *并发的劣势:... (2)资源分配: 单线 ...
- 深入浅出NodeJS——数据通信,NET模块运行机制
互联网的运作,最根本的驱动就是信息的交互,NodeJS 在数据交互这一块做的很带感,异步编程让人很惬意,关于 NodeJS 的数据通信,最基础的两个模块是 NET 和 HTTP,前者是基于 TCP 的 ...
随机推荐
- Hash表的扩容(转载)
Hash表(Hash Table) hash表实际上由size个的桶组成一个桶数组table[0...size-1] . 当一个对象经过哈希之后.得到一个对应的value , 于是我们把这个对象放 ...
- [转]Laravel 4之控制器
Laravel 4之控制器 http://dingjiannan.com/2013/laravel-controller/ 控制器 通常Laravel控制器文件放在app/controllers/目录 ...
- freemarker书写select组件错误摘要(七)
1.错误叙述性说明 六月 26, 2014 11:26:27 下午 freemarker.log.JDK14LoggerFactory$JDK14Logger error 严重: Template p ...
- Oracle—RMAN备份(二)
在Oracle RMAN备份(一)中,对各种文件在RMAN中备份进行了说明, 一.备份集的复制 在RMAN 备份中,可以备份其自己的备份,即备份一个文件放在多个目录下,oralce支持最多备份四个. ...
- iOS面试题集
现在寒假时间在家里面无法敲代码了,但是自己总要找些事情来做,回头想想马上就要开始就业了,所以不免要参加面试,于是便开始了面试题集的浏览和探索,今天下午我看了一部分的面试题感觉还是挺实用的,所以以后还是 ...
- lucene评分推导公式
在进行Lucene的搜索过程解析之前,有必要单独的一张把Lucene score公式的推导,各部分的意义阐述一下.因为Lucene的搜索过程,很重要的一个步骤就是逐步的计算各部分的分数. Lucene ...
- C# using垃圾回收详解
简介 定义一个范围,将在此范围之外释放一个或多个对象. 语法 using (Font font1 = new Font("Arial", 10.0f)) { } C# 语言参考 主 ...
- 表单提交---前端页面模拟表单提交(form)
有些时候我们的前端页面总没有<form></form>表单,但是具体的业务时,我们又必须用表单提交才能达到我们想要的结果,LZ最近做了一些关于导出的一些功能,需要调用浏览器默认 ...
- centos 6.4从源码安装mysql 5.6笔记
上周在安装mysql时遇到了些许麻烦,今天整理下. 在代码目录建立obj文件夹. 在obj目录下,执行cmake .. -DXXX // XXX表示一些参数,详见http://dev.mysql.c ...
- 轻量级jquery框架之--面板(panel)
面板需求: (1)支持可拖拽,面板将作为后期的布局组件.window组件.alert组件的基础. (2)支持自定义工具栏,工具栏位置定义在面板底部,工具栏依赖toolbar组件. (3)支持加载JSO ...