海量数据大行其道的今天 node.js 在IO方面如何异步非阻塞
以其高性能,异步IO著称,当然node.js 在 stream 上的异步也非常到位. 我们一般理解的异步请求是这样的: 同时处理多件件事件 A,B,C,D,E,F,G .... 如果用.net语言去处理这些事情可能有2钟情况 (1) A,B ..... G 按照顺序一件一件处理,最后得到返回值. (2)开启多线程去同时执行多个事件. 而node是单线程处理语言,天生就不是富二代,资源还有限......上帝造物的时候是公平,当你发现关上一扇门的话,同时肯定会为你开一扇窗.所以node 有了异步回调. 所以node.js下的处理可能是这样的: A,B ...... G 依然是按照这个顺序处理,但是得到的返回值可能是先返回 G 然后得到 A 的.
那么IO操作中 stream 是如何处理的呢?
var fs = require('fs') fs.readFile('/etc/hosts', function (err, buffer) { if (err) { return console.error(err.stack) } console.log(buffer.toString('utf8')) })
这种方式是读取一个文件到内存中,然后再输出到控制台,必须先全部读取文件在先,而后从内存写入到console,中间可能有等待,当然这是个非常小的文件. 上面的方法和其他同步语言处理文件貌似没有俩样,如果遇到特别大的文件,而且node.js是单进程,这样必须会堵塞啊,其实node.js 还有一种在IO操作文件上的异步. 我的cod文件夹下有个比较大的文件文件
node.js 使用另外一种异步处理文件流的方式读取大文件.
var fs=require('fs'); var http=require('http'); var server=http.createServer(function(req,res){ var stream=fs.createReadStream(__dirname+'/data.txt',{flags:'r'}); stream.pipe(res); }); server.listen(9999);
和上面的代码比较,有俩处变动,fs 用了 createReadStream , stream.pipe
这种方式并不是一下把整个文件读入内存,而是从文件变为读取流后有进过管道(pipe) 到 response 流中.
通俗点讲就是相当于拿了一根管子,一头是 file stream 入口,一头是 response stream 出口,有了这个管子读取再大的文件都是易如反掌.
下面我们用2个桶子来比喻:
如果都从顶部注水,上边的水桶必须关闭水龙头后才能执行下一步操作.
下边的水桶因为本身自带了一个小水龙头,所以不需要关闭注水水龙头也可以进行下一步操作.那么下边的水桶工作模式是异步无阻塞的.
所以上面的代码把6.7M的文件一点一点读出来再通过管道一点一点response到页面,对用户来说是不需要等待的,这种流的异步处理非常有效率.