非阻塞I/O事件驱动

Posted yuyujuan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非阻塞I/O事件驱动相关的知识,希望对你有一定的参考价值。

在 Java、php 或者.net 等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约 2MB 内存。也就是说,理论上,一个 8GB 内存的服务器可以同时连接的最大用户数为 4000 个左右。要让 Web 应用程序支持更多的用户,就需要增加服务器的数量,而 Web 应用程序的硬件成本当然就上升了。node.js 不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞 I/O、事件驱动机制,让 Node.js 程序宏观上也是并行的。使用 Node.js,一个 8GB 内存的服务器,可以同时处理超过 4 万用户的连接。

但是在实际过程中,非阻塞也会产生一定的问题,例如,我们需要从后台请求数据,然后拿到这些数据以后,执行某些操作,但是由于非阻塞,不能控制获取数据的时间,后续的操作就会出现问题。

技术图片

在上面例子中,我们希望先执行第一个打印,然后执行文件读取,最后执行第四个打印。但是由于Node是非阻塞的,在执行到文件读取的时候,由于文件大小的原因,需要一定的时间,在这个时间里,有并行处理了第四个打印,等第四个打印执行了,前面的文件读取才执行结束,于是就有了下面的输出

技术图片

同样,在下面的例子中,同样由于执行文件读取的时间过长,在读取文件的时候,并发执行了打印事件,所以打印的时候,并没有数据。

技术图片      技术图片

可是在实际项目中,这种结果是不能接受的,为了保证能打印出数据,我们希望在文件结束后,再执行打印事件,下面两种办法就是实现这个要求。

回调函数

 技术图片   技术图片

event模块处理异步

Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件。

在使用events 模块的时候,需要先引入改模块,并创建 EventEmitter对象。

var events=require(‘events‘);
var EventEmitter=new events.EventEmitter();

然后在需要等待上面执行完毕再执行的事件里面,绑定事件和事件处理程序

eventEmitter.on(‘eventName‘, eventHandler);

最后,在处理费时程序的地方,触发上面的绑定

eventEmitter.emit(‘eventName‘);

绑定和触发的事件名称需要保持一致。

按照上面的方式,我们可以对前面的例子进行调整:

 技术图片   技术图片

event模块

Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列,所有这些产生事件的对象都是 events.EventEmitter 的实例,EventEmitter 的核心就是事件触发与事件监听器功能的封装。EventEmitter 对象如果在实例化时发生错误,会触发 error 事件。当添加新的监听器时,newListener 事件会触发,当监听器被移除时,removeListener 事件被触发。

基础用法

技术图片  技术图片

多个监听器

EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持 若干个事件监听器。当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。

 技术图片  技术图片

 

以上是关于非阻塞I/O事件驱动的主要内容,如果未能解决你的问题,请参考以下文章

非阻塞I/O事件驱动

Node.js简概

Node-学习笔记

WEB服务-Nginx之1-网络IO模型和常用事件驱动模型

NodeJS:特性&环境&测试

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