node学习笔记03(异步I/O)

用户体验javascript

异步的概念首先在web2.0中火起来,是由于浏览器中的javascript在单线程上执行,html

并且它还与UI的渲染共用一个线程,这意味着javascript在执行的时候UI渲染和响应式处于停滞状态的前端

若是脚本的执行时间超过100毫秒,用户就会感到页面卡顿,觉得网页中止响应.java

若是网页临时须要获取一个网络资源,经过同步的方式获取,那么javascript则须要等待资源彻底node

从服务器端获取后才能继续执行,这期间UI将停顿,不响应用户的交互行为.web

而若是采用异步请求,在下载资源期间,javascript和UI的执行都不会处于等待状态.编程

同理,前端经过异步能够消除UI阻塞的现象,可是前端获取资源的速度也取决于后端的响应速度windows

如今又一情景,前端箱后端请求两个资源后端

假设获取资源s1须要耗时n1 获取资源s2须要耗时n2浏览器

若是采起同步的方式,代码大体以下

getData(s1);//耗时n1

getData(s2);//耗时n2

那么总耗时即为n1 + n2

若是采用异步的方式

getData(s1, function(result){

    //耗时n1

});

getData(s2, function(result){

    //耗时n2

});

那么总耗时即为max(n1, n2)

随着应用复杂性的总消耗,情景将会变成n1 + n2 + n3 + ....和max(n1, n2, n3,......)

同步于异步的优点将会凸显出来

另外一方面,随着网站的或应用的不断膨胀,

数据将会分布到多台服务器上,分布式将会是常态

也就意味着n1,n2,n3...的值会线性增加,这也会方法异步和同步在性能方面的差别

下面列出从cpu一级缓存到网络的数据访问所须要的开销

    I/O类型                          花费的CPU时钟周期

cpu一级缓存                              3

cpu二级缓存                              14

内存                                        250

硬盘                                        41000000

网络                                        240000000

资源分配

排除用户体验体验的因素,咱们从资源分配的层面来分析一下异步I/O的必要性

假设业务场景中有一组互不相关的任务须要完成,,现行得主流方法有如下两种

单线程串行依次执行

多线程并行完成

分别的优缺点

单线程

优势:比较符合编程人员按顺序思考的思惟方式,它依然是最主流的编程方式

缺点:性能问题突出,任意一个略慢的任务都会致使后续执行代码被阻塞,

多线程

优势:若是建立多线程的开销小于并行执行,那么多线程是首选的,

        在多核cpu上可以有效提高cpu的利用率,这个优点毋庸置疑

缺点:建立线程和执行期线程上下文切换开销较大,另外在稍复杂的业务中

        还经常面临锁,状态同步等问题,这是多线程被诟病的主要缘由

单线程同步编程模型会因阻塞I/O致使硬件资源得不到更优的使用,多线程编程模型也由于

编程中的死锁,状态同步等问题让开发人员头疼

node在二者之间给出了他的方案:利用单线程,远离多线程死锁,状态同步等问题

利用异步I/O,让单线程远离阻塞,以更好地使用cpu

而且,为了弥补单线程没法利用多核cpu的缺点,node还提供了相似前端浏览器中的

Web Workers的子进程,该子进程能够经过工做进程高效地利用CPU和I/O

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

在node中,常常提早异步非阻塞I/O的概念,貌似异步与非阻塞彷佛是同一回事,

就实际效果而言,异步和非阻塞都达到了咱们并行I/O的目的,可是从计算机内核I/O而言

异步/同步 和 阻塞/非阻塞其实是两回事

这里因为本人对系统底层的实现并不太了解,因此只能上网找了些资料

http://blog.csdn.net/historyasamirror/article/details/5778378

http://www.zhihu.com/question/19732473

http://www.cppblog.com/converse/archive/2009/05/13/82879.html

上面列举一些可供参考的文章和知乎上的提问可供你们参考

我也暂时没能力很好地为异步/同步 和 阻塞/非阻塞的概念作解析,

node在*nix平台下自行实现了线程池来完成异步I/O

在windows平台下则采用了IOCP实现异步I/O

须要强调一点的是,这里的I/O不只仅只限于磁盘文件的读写,*nix将计算机抽象了一番,

磁盘文件,硬件,套接字等几乎全部计算机资源都被抽象为了文件,所以阻塞和非阻塞的状况一样能适合套接字等

另外一个须要强调的地方在于咱们时常提到的node是单线程,这里的单线程仅仅只是javascript执行在单线程中罢了

在node中,不管是*nix仍是windows平台,内部完成I/O任务的另有线程池

node的异步I/O

首先,咱们着重强调一下node自身的执行模型-时间循环

正是它使得回调函数十分广泛

但进程启动是,node便会建立一个相似while(true)的循环

每执行一次循环体的过程咱们称为Tick,每一个Tick的过程就是查看是否有事件待处理,

若是有,就取出时间及其相关的回调函数,若是存在关联的回调函数,就执行他们,而后进入下个循环

若是再也不有事件处理,就退出进程

每一个事件循环中有一个或者多个观察这,而判断是否有事件要处理的过程就是向这些观察者询问是否有要处理的事件

浏览器采用了相似的机制,时间可能来自用户的点击或者加载某些文件时产生,

而这些产生的事件都有其对应的观察者,在node中,事件主要来源于网络请求,文件I/O等,

这些事件对应的观察者有文件I/O观察者,网络I/O观察者等,观察者将事件进行了分类.

时间循环是一个典型的生产者/消费者模型,异步I/O,网络请求等则是事件的生产这,

源源不断为node提供不一样类型的时间,这些事件被传递到对应的观察者哪里,事件循环则从观察者那里取出时间并处理

node中的单线程与I/O线程池之间看起来有些悖论的样子,事实上,在node中,除了javascript是单线程的,

因此按常识很容易理解为它不能充分利用多核cpu,事实上,在node中,除了javascript是单线程外,node自身实际上是多线程的

只是I/O线程使用的cpu较少,另外一个须要重视的观点则是,除了用户代码没法并行执行外,全部的I/O(磁盘I/O和网络I/O)则是能够

并行的,

相关文章
相关标签/搜索