• Node 高性能异步I/O框架


    1,什么是Node?

          首先介绍下什么是node

              1,单线程

                   node保持了javascript在浏览器中单线程的特点,Node中,Javascript与其余线程无法共享任何状态。

                   单线程好处:不用处处在意状态的同步,没有死锁,也没有线程上下文切换带来的性能开销。

                   单线程坏处:无法利用多核cpu,错误会引起整个应用退出,应用的健壮性值得考验,大量计算占用CPU无法继续调用异步I/O。

                  (注意:针对这些单线程坏处,node都有解决方案,这里不谈)

              2,跨平台 (基于libuv)

    兼容Windows和*nix平台主要得益于Node在架构层的的改动,它在操作系统与Node与操作系统之间构建了一层平台层框架,即libuv。目前,libuv已经是许多系统实现跨平台的基础组件。

    通过良好的架构,Node的第三方C++模块也可以借助libuv实现跨平台,目前,除了没有保持更新的C++模块外,大部分C++模块都能实现跨平台的兼容。

              3,模块机制

                    Java有类文件,Python有import机制,Ruby有require,PHP有include和require。浏览器端Javascript是没有标准的模块机制的,只能通过<script>标签引入代码显得杂乱无章,

                   语言本身没有组织和约束能力,开发者不得不通过命名空间等方式人为约束代码。-》AMD,CMD。

                  CommonJS规范:希望javascript能够在任何地方运行。

                     CommonJS的规范提出主要是为了弥补当前Javascript没有标准的缺陷,以达到像Python,Ruby和Java具备开发大型应用的基础能力,而不是停留在小脚本程序的阶段.NodeJS是这种规范的实现

                     CommonJS规范涵盖了模块,二进制,Buffer,字符集编码,I/O流,进程环境,文件系统,套接字,单元测试,Web服务网管接口,包管理等。

                      CommonJS有很多实现,其中不乏很多大名鼎鼎的项目,比如 说:Apache的CouchDBnode.js等。但这些项目大 部分只实现了CommonJS的部分规范。具体的项目和实现部分参见官方网站的说                        明:http://commonjs.org/impl/

                       

                        Node模块实现

              4,应用场景

                    I/O密集型

                   是否不擅长cpu密集型?

          

    2, 异步的原理。        

                但凡这种「既是单线程又是异步」的语言有一个共同特点:它们是 event-driven 的。驱动它们的 event 来自一个异构的平台。

          异步调用(封装参数)-》线程池(iocp)-》事件循环(监听者-》执行回调函数)

            阻塞I/O与非阻塞I/O:操作系统内核对于I/O只有两种方式:阻塞与非阻塞。

                   [注]:操作系统对计算机进行了抽象,将所有输入输出设备抽象为文件,内核在进行文件I/O操作时,通过文件描述符进行管理,而文件描述符类似于应用程序与系统内核

           之间的凭证。应用程序如果需要进行I/O调用,需要先打开文件描述符,然后根据文件描述符去实现文件的数据读写。此处阻塞/O与非阻塞I/O的区别在于阻塞I/O完成整个获取

           数据的过程,而非阻塞I/O则不带数据直接返回,要获取数据,还需要通过文件描述符再次读取。

                 阻塞I/O的一个特点是一定要等待系统内核层面完成所有数据操作后,调用才结束。以读取磁盘文件为例:系统内核在完成磁盘寻道,读取数据,复制数据到内存中之后这个调

           用才结束。如图:

                          

                阻塞I/O造成了CPU等待,浪费了等待时间,CPU的处理能力不能得到充分利用。为了提高性能,内核提高了非阻塞I/O。非阻塞I/O跟阻塞I/O的区别为调用之后立即返回,如图:

               

                 非阻塞I/O返回之后,CPU的时间片可以用来处理其他事务,此时性能提升是明显的。

                但非阻塞I/O也存在一些问题。由于完整的I/O没有完成,立即返回并不是业务层期望的数据,而仅仅是打当前调用的状态,为了获取完整的数据,应用层序需要重复调用I/O操作来

               确认是否完成。这种重复的调用判断操作是否完成的技术叫做轮询。[注]:任意技术都并非是完美的,阻塞I/O造成CPU等待浪费,非阻塞I/O带来的麻烦却是需要轮询取确认是否

              完全完成数据获取,他会让CPU处理状态判断,是对CPU的资源浪费。

              轮询技术是有演进的,以减少I/O状态判断的CPU损耗。从read->select->poll->epoll。具体情况这里不谈。

             理想的非阻塞异步I/O:我们期望的完美的异步I/O应该是应用程序发起非阻塞调用,无需通过遍历或者事件唤醒灯方式轮询,可以直接处理下一个任务,只需要在I/O完成后通过信号

             或者回调函数讲数据传递给应用程序即可,如下图:

                     

            幸运的是,在Linux中存在这中方式,它提供一个异步的I/O方式(AIO)就是通过信号或回调来传递数据的。但不幸的是,只有Linux中有,并且AIO只支持内核I/O中的O_DIRECT方法

           读取,并且无法利用系统缓存。

          现实的异步I/O

                  现实肯定比理想要骨感一些,但是要达成异步I/O的目标,也并非难事。前面我们讲场景都限定在单线程的状态下,多线程的方式就是另一番风景了。通过让部分线程进行阻塞I/O

          或者非阻塞I/O加轮询技术来完成数据获取,让一个线程进行计算,通过线程之间的同学讲I/O得到数据进行传递,这就轻松实现了异步I/O(尽管是模拟的)。

               

                      

            [注]:这里的I/O不仅仅只局限于磁盘读写*nix将计算机抽象了一番,磁盘文件,硬件,套接字等几乎所有计算机资源都被抽象成了文件,因此这里的描述的阻塞和非阻塞的情况

             同样适合套接字等。

             [注]:我们虽然时常提到Node是单线程的,这里的单线程仅仅指的是Javascript执行在但形成中罢了。在Node中,无论是什么平台,内部完成的I/O任务都是另有线程池的。

     3,为什么要用异步?

          

    4,常用的异步库

           Deferred是前端解决异步操作的一种编程范式,后来出现的Promise规范更是让其普适性大大提高。不过Promise规范也存在分岐。现在最流行的是Promise/A+规范。

     4,1  Promise

          在这些Promise的实现类库中,主要对两种类型的类库进行介绍。一种是被称为 Polyfill 的类库,另一种是即具有 Promises/A+兼容性 ,又增加了自己独特功能的类库。

      

      PolyFill

           只需要在浏览器中加载Polyfill类库,就能使用IE10等或者还没有提供对Promise支持的浏览器中使用Promise里规定的方法。也就是说如果加载了Polyfill类库,就能在还不支持Promise          的环境中,运行Promise。

         1,jakearchibald/es6-promise

           一个兼容 ES6 Promises 的Polyfill类库。 它基于 RSVP.js 这个兼容 Promises/A+ 的类库, 它只是 RSVP.js 的一个子集,只实现了Promises 规定的 API。

         2,yahoo/ypromise

          这是一个独立版本的 YUI 的 Promise Polyfill,具有和 ES6 Promises 的兼容性。 

        3,getify/native-promise-only

           以作为ES6 Promises的polyfill为目的的类库 它严格按照ES6 Promises的规范设计,没有添加在规范中没有定义的功能。 如果运行环境有原生的Promise支持的话,则优先使用原生的          Promise支持。一个兼容 ES6 Promises 的Polyfill类库。 它基于 RSVP.js 这个兼容 Promises/A+ 的类库, 它只是 RSVP.js 的一个子集,只实现了Promises 规定的 API。 
     

      Promise扩展类库

           1,kriskowal/q

           使用过Node.js的人可能会知道Q模块,Q实现了Promises和 Deferreds等规范,在Node.js中环境或浏览器环境中使用。

          2,then/promise

           一个Promise/A+简单实现模块,除实现then方法外,还扩展一些标准外的方法,在Node.js中环境或浏览器环境中使用。

          3,petkaantonov/bluebird

        bluebird类库除了兼容Promise规范之外,还对Promise对象进行了一定的扩展,如:取消promise对象的运行等。另外,还在运行效率上进行了一定的优化。bluebird也是一             个npm模块,可以在Node.js中环境或浏览器环境中使用。 

       其他
          Async.js是一个流程控制工具包,提供了直接而强大的异步功能。参考这里:http://blog.fens.me/nodejs-async/
     《深入浅出node》作者朴灵写的EventProxy参考:https://github.com/JacksonTian/eventproxy   
        大名鼎鼎的co正是TJ大神基于ES6的一些新特性开发的异步流程控制库,基于它所开发的koa更是被视为未来主流的web框架。

       Wind.js   https://github.com/JeffreyZhao/wind   http://blog.fens.me/nodejs-async-windjs/

     

     

     

                 

          

  • 相关阅读:
    第一次用NUnitAsp
    IT能够解决所有的商业问题吗?
    在这种东西里面,你会自在吗?
    看了段.net show之后的感想
    获取当前数据库中所有表的记录数
    对瀑布模型各阶段的解释
    Linux内核中的slab/slob/slub 在搞晕前先记下来
    分布式事务AT、TCC、Saga、XA 模式分析对比
    读懂Windows的“虚拟内存”为你量身定制
    示范NTFS 卷上的硬链接
  • 原文地址:https://www.cnblogs.com/emory/p/5082314.html
Copyright © 2020-2023  润新知