[译]理解node.js事件轮询

在ManUel Kiessling的《The Node Beginner Book》中提到了Node.js的事件轮询。

其中提到Mixu的博文:《Understanding the node.js event loop》

原文出处:http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/

以下是我的译文:

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

The-cost-of-IO.jpg

因此在现代编程技术中,等待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('&lt;html&gt;&lt;head&gt;&lt;title&gt;Hello&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;h1&gt;Return from async DB query&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;');
     c.end();
    }
);

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

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

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

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

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

bucket_3.jpg

事件轮询是“一个掌握和处理外部事件并且把他们转成回调调用的实体”。因此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中发生某种事件时执行。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容