Node.js的异步I/O

Linux操作系统的I/O模型

JAVA的NIO引入了异步I/O,而Node.js宣称的就是异步编程,I/O自然是异步的。其实操作系统在很早就引入了异步I/O的概念,如下图(摘自Unix网络编程中的图片):

我对上图的理解有几点:

  1. 从IO设备读取数据到用户内存的整个过程都是由系统内核来完成;
  2. 数据总是先被拷贝到内核缓冲区,再由内核缓冲区拷贝到用户内存;
  3. 除了异步I/O,其余4种I/O模型其实都是阻塞的,至少在数据从内核拷贝到用户内存时是阻塞的;
  4. 虽然异步I/O看上去是理想解决方案,但实现上现在用得最多的应该是多路I/O复用,有select、poll、epoll的实现,性能最好的是epoll;
  5. 异步I/O现在被认为有缺陷,仅支持O_DIRECT而无法支持系统缓存。

Node.js中的异步I/O

因为内核中的异步I/O有缺陷,现实中的异步I/O通常由用户态的线程池模拟完成,如下图:

Node.js中原本使用了libeio异步I/O库,在v0.9.3后改为自己实现的线程池来完成异步I/O。所以在Node.js中,除了用户的Javascript代码是单线程外,所有I/O都是多线程并行执行的。

Node.js中的异步I/O调用

Node.js通过事件循环的模式运行,在每一个循环的过程中,通过询问一个或多个观察者来判断是否有事件要处理,而观察者可以有文件I/O观察者、网络I/O观察者等。

Node.js中异步I/O调用的大致流程如下:

  • 发起I/O调用

    1. 用户通过Javascript代码调用Node核心模块,将参数和回调函数传入到核心模块;
    2. Node核心模块会将传入的参数和回调函数封装成一个请求对象;
    3. 将这个请求对象推入到I/O线程池等待执行;
    4. Javascript发起的异步调用结束,Javascript线程继续执行后续操作。
  • 执行回调
    1. I/O操作完成后,会将结果储存到请求对象的result属性上,并发出操作完成的通知;
    2. 每次事件循环时会检查是否有完成的I/O操作,如果有就将请求对象加入到I/O观察者队列中,之后当做事件处理;
    3. 处理I/O观察者事件时,会取出之前封装在请求对象中的回调函数,执行这个回调函数,并将result当参数,以完成Javascript回调的目的。

微信订阅号:

源文地址:http://blog.gopersist.com/2015/03/09/aio/

时间: 2024-10-05 06:51:22

Node.js的异步I/O的相关文章

【译】深入理解python3.4中Asyncio库与Node.js的异步IO机制

转载自http://xidui.github.io/2015/10/29/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3python3-4-Asyncio%E5%BA%93%E4%B8%8ENode-js%E7%9A%84%E5%BC%82%E6%AD%A5IO%E6%9C%BA%E5%88%B6/ 译者:xidui原文: http://sahandsaba.com/understanding-asyncio-node-js-python-3-4.html 译者前言 如

对Node.js的异步机制的思考

Node.js的异步机制是其最大的特色,异步可以应对高并发,具有很好的性能. 但是如果在某个方法里,涉及到数据库的多层查询,异步机制反而成为阻碍.当执行完第一层SQL后,根据所得的结果集(rows)进行结果集进行遍历时,每次遍历的结果作为where条件再执行下一层SQL时,下一层及以后的SQL并不会执行,而是在结果集(rows)遍历到最后时,才执行下一层SQL. 这时,若SQL只有两三层,其实倒还好,可以合并SQL:但是SQL层数多了之后,这种异步机制却是最大的阻碍.这时,就需要用到Node.j

node.js的异步I/O、事件驱动、单线程

nodejs的特点总共有以下几点 异步I/O(非阻塞I/O) 事件驱动 单线程 擅长I/O密集型,不擅长CPU密集型 高并发 下面是一道很经典的面试题,描述了node的整体运行机制,相信很多人都碰到了.这道题背后的原理就是nodejs代码执行顺序 setTimeout(function() { console.log('4'); },0) setImmediate(function() { console.log('5'); }) let s = new Promise(function(res

node.js 多异步之间的协作方案

<深入浅出node.js> P77 学习 ///用于处理多个事件对应一个侦听器的情况var count = 0; var results = {}; var done = function (key, value){ results[key] = value; count++; if (count === 3){ ///渲染页面 render(results); } }; fs.readFile(template_path, "utf8", function(err, te

node.js接收异步任务结果的两种方法----callback和事件广播

事件广播 发送方调用emit方法,接收方调用on方法,无论发送方或是接收方,都会工作在一个频道 声明了一个模块,用于读取mime.json中的记录 var fs = require('fs'); var events = require('events'); var eventemitter = new events.EventEmitter(); var getmimetype = function (path,eventemitter,suffix) { fs.readFile(path,f

Node.js入门:异步IO

异步IO 在操作系统中,程序运行的空间分为内核空间和用户空间.我们常常提起的异步I/O,其实质是用户空间中的程序不用依赖内核空间中的I/O操作实际完成,即可进行后续任务. 同步IO的并行模式 多线程单进程    多线程的设计之处就是为了在共享的程序空间中,实现并行处理任务,从而达到充分利用CPU的效果.多线程的缺点在于执行时上下文交换的开销较大,和状态同步(锁)的问题.同样它也使得程序的编写和调用复杂化. 单线程多进程 为了避免多线程造成的使用不便问题,有的语言选择了单线程保持调用简单化,采用启

Node.js中的异步I/O是如何进行的?

Node.js的异步I/O通过事件循环的方式实现.其中异步I/O又分磁盘I/O和网络I/O.在磁盘I/O的调用中,当发起异步调用后,会将异步操作送进libuv提供的队列中,然后返回.当磁盘I/O执行完成之后,会形成一个事件,事件循环的过程中发现该事件后,会将其消费.消费过程就是将得到的数据和传入的回调函数执行. 网络I/O与磁盘I/O的差异在于它不需要线程池来进行处理,而是在每次时间循环的过程中通过IOCP/epoll/kqueue/event ports来获取网络I/O的 事件队列. 摘自:<

node js异步IO机制

同步和异步的概念描述的是用户线程与内核的交互方式:同步是指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行:而异步是指用户线程发起IO请求后仍继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数. 阻塞和非阻塞的概念描述的是用户线程调用内核IO操作的方式:阻塞是指IO操作需要彻底完成后才返回到用户空间:而非阻塞是指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成. node js的异步I/O是它的一个重要功能,为了讲清楚这个机制,先说

Node.js的循环与异步问题

Node.js 的异步机制由事件和回调函数实现,一开始接触可能会感觉违反常规,但习惯 以后就会发现还是很简单的.然而这之中其实暗藏了不少陷阱,一个很容易遇到的问题就是 循环中的回调函数,初学者经常容易陷入这个圈套.让我们从一个例子开始说明这个问题. var fs = require('fs'); var files = ['a.txt', 'b.txt', 'c.txt']; for (var i = 0; i < files.length; i++) { fs.readFile(files[i