Node.js事件轮询解析
沉沙 2018-07-09 来源 : 阅读 724 评论 0

摘要:本篇Node.js教程探讨了Node.js事件轮询,希望阅读本篇文章以后大家有所收获,帮助大家对Node.js的理解更加深入。

Node.js事件轮询解析

关于Node.js的第一个基本概念是I/O操作的开销是巨大的:

 Node.js事件轮询解析

因此在现代编程技术中,等待I/O操作完成是最浪费时间的。这里列举了几种方式来解决这种性能影响,(来自 Sam Rushing):

· 同步处理:你一次处理一个请求,每个请求依次处理。优点:简单;缺点:任何一个请求都会阻塞其他请求。

· 开启一个新进程:你为每个请求开启一个新的进程。优点:简单;缺点:不利于扩展,大量的链接意味着大量的进程。fork()是Unix编程的一个锤子,因为它非常有用,因此常被过度使用来解决任何看起来像一个钉子的问题。

· 线程:为每个请求开启一个新的线程。优点:简单,而且比开启新进程对内核更友好,因为线程的开销通常会更小一些;缺点:不是所有的机器都支持线程,而且对于要处理共享资源的情况,多线程会很快变得过于复杂。

第二个基本概念是,如果要为每个线程都开启一个新的链接,这样的内存开销是巨大的(比如:和Nginx相比之下,Apache内存耗尽的情况)。

Apache是多线程的:它为每个请求开启一个新的线程(或进程,这取决于实际配置)。随着并发连接数量的增加,以及需要更多线程同时为多个的客户端服务时,你可以看到它是如何消耗内存的。Nginx和Node.js不是多线程的,因为线程和进程的内存开销太大了。它们是单线程、基于事件的。它解决了处理众多连接所产生的线程/进程的消耗的问题。

Node.js让你的代码保持单线程...

它是真的只有一个线程在运行:你不能并行地执行程序;例如模拟一个"sleep"会阻塞服务器一秒钟:

while(new Date().getTime() < now + 1000) {  

   // do nothing  

}

因此当上面这段代码在执行的时候,node.js将不会响应任何其它来自客户端的请求,因为它只能有一个线程来执行你的代码。此外,如果你执行cpu密集任务,比如重设图像的大小,它也会阻塞所有请求。

...然而,除了你的代码,其它的一切都是并行执行的

单线程没办法让代码并行执行。然而,所有的 I/O 都是事件驱动、异步的。所以下面的代码不会阻塞

server:
 c.query(
   'SELECT SLEEP(20);',
   function (err, results, fields) {
     if (err) {
       throw err;
     }
     res.writeHead(200, {'Content-Type': 'text/html'});
     res.end('<html><head><title>Hello</title></head><body><h1>Return from async DB query</h1></body></html>');
     c.end();
    }
);

如果你在一次请求中执行上面的代码,当数据库sleep时,其它请求也会被立即处理。

为什么异步更好?我们应该什么时候从同步转移到异步/并行执行呢?

使用同步执行也是不错的,因为它简化了代码的编写(相比于多线程,并发性问题有导致WTFs的趋势)

在Node.js中,你不必担心后台是怎么处理的:当你在做I/O操作时只需要使用回调就可以了;而且它保证了你的代码永远不会中断,I/O操作不会阻塞其它请求,同时也无需承担每个请求所产生的线程/进程的开销成本(例如Apache中的内存开销)。

在I/O操作中使用异步是很好的选择,因为I/O操作的开销比单纯地执行代码要高得多,我们不应该单纯地等待I/O操作,而是应该在这时做一些事情。

事件轮询是“一个掌握和处理外部事件并且把他们转成回调调用的实体”。因此I/O调用的同时,server就可以去处理另一个请求。在一次I/O调用中,你的代码会保存回调函数并把控制权返回到node.js运行时。当数据可访问时,就可以执行这个回调了。

当然,在后端,还是有数据库访问和流程执行的线程和进程。但是,这些都不需要你的代码直接实现,因此除了了解I/O交互之外,你不了解它们。比如,从每个请求的角度来看,数据库或其它流程需要异步,因为这些线程的结果会通过事件轮询返回给你代码。和Apache模块相比,它省去了许多内存的消耗,因为不是每个链接都需要更新线程;只有当你真正确定某些进程是并行运行时才会更新线程,即使这样的操作也是通过Node.js来处理的。

除了I/O调用以外,Node.js所期望的所有请求都能被快速返回;比如CPU密集型任务分解到另一个可与事件交互的进程,或使用WebWorkers等抽象交互时。这(显然)意味你不能并行执行你的代码,除非后台有个另一个线程,你可以通过事件与之交互。基本上,所有发出事件的对象(例如 EventEmitter实例)都支持异步均衡交互。并且可以用这种方式组织代码交互,比如在Node.js中使用文件、套接字或子进程等EventEmitters。多核可以使用这种方法;另见:node-http-proxy。

内部实现

在内部,node.js依靠libev来提供事件轮询,这是libeio的补充,它使用线程池来提供异步I/O操作。要了解更多信息,请参阅libev文档。

因此我们应该如何在Node.js中实现异步?

Tim Caswell在他的演讲中描述了这些模式:

· First-class Function(译者注:该类型的值可以作为函数的参数和返回值,也可赋给变量)。比如,我们将函数作为数据传递,并在需要时执行它们。

· Function composition。又称为匿名函数或闭包,在基于时间的I/O中发生某种事件时执行。


本文由职坐标整理发布,学习更多的Node.js相关知识,请关注职坐标WEB前端Node.js频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程