了解nodejs中的事件轮询(eventloop)

很久以前翻译的,忘了出处(:з」∠)

首先需要知道的是,node.js的 I/O是异常昂贵的

The cost of I/O
L1-chache                               3 cycles
L2-cache                               14 cycles
RAM                                   250 cycles
Disk                             41000000 cycles
Network                         240000000 cycles

所以一旦当前的编程技术是通过等待I/O完成的话,那将是非常浪费的一件事情,现在有几种方法可以处理对于性能的影响(可以参看异步套接字编程)

  1. 同步: 依次处理每个请求,并且每次只处理一个请求. 优点: 非常的简单,缺点: 一个请求就足以阻塞出整个应用
  2. 创建一个新的进程(fork a new process): 创建一个新的进程来处理新的请求. 优点: 也很简单,缺点: 多少个连接就意味着多少个进程,fork()是Unix程序员的锤子,因为所有问题看上就像个钉子,不过它通常都是多余的力量(overkill)
  3. 线程: 启动一个新线程来处理请求. 优点: 也很简单,比起让内核(kernel)使用fork()来说要更加温柔些,毕竟线程通常就有很多,而且资源开销更小,缺点: 机器有可能并没有好的线程程序,导致可能非常的复杂或降低速度,附送的还有对于共享资源的访问也可能出现问题

其次,第二个问题是,线程共享的链接缓冲池,也是非常昂贵的

Apache 是多线程的,

每个请求都会生成一个线程或进程,它取决于conf,你可以看到这玩意是怎么吃内存的,而且随着并发连接数量的增多,所需要的线程也就越多,比如什么Nginx,节点等
而js并不是多线程,线程和进程会带来沉重的内存成本,所以它是基于事件的单线程,通过这样来消除成千上万的线程/进程,并且将所有需要处理的问题都绑定在一个线程上

Node.js 始终保持着单线程的优良传统

而它毫无疑问也是一个真正的单线程 : 在这里,你无法执行任何的并行代码,比如做一个延迟(sleep)来阻止服务器一秒:

while(new Date().getTime() < now + 1000) { 
// do nothing
 }

而在这期间,js不会回应任何来自客户的请求,因为它只有一个线程执行的代码,或者如果你会一些别的什么cpu什么的代码,说: 给我搞搞图片大小,就算这样,js依然会阻止这些请求

不过,不管什么都好,都是离不开并行的,尤其是你的代码

代码是没办法并行的运行在单个请求上的,不过,所幸所有的I/O都是一个事件并且异步的,所以下面这种方法并不会阻塞服务器

 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线程问题)
(Having synchronous execution is good, because it simplifies writing code (compared to threads, where concurrency issues have a tendency to result in WTFs).)

在node.js中,当你正在处理I/O的时候,不应该担心后台的问题,解决好你的回调问题,还有保证你的代码不会被打断,因为I/O并不会阻止其他请求,所以也不必承担线程/进程的请求成本(比方说在Apache中的内存开销)

异步I/O是非常不错的,因为I/O比大多数的代码开销更大,更昂贵,所以我们应该在等待I/O(阻塞过程)的过程中做更多的事情
(这个机制很大程度上是源于js本身就是一个非阻塞I/O)

事件轮询(eventloop)"一个解决和处理外部事件时将它们转换为回调函数的调用的实体(entity)",所以当代码调用一个I/O的时候,node.js可以从这个请求切换到另一个请求,当调用I/O的时候,代码将会保存回调并且返回某些结果给node.js运行环境中,只有当数据实际可用的时候(或者说不那么阻塞了(sleep事件过了等)),回调便会被调用

当然,在后台中,会有来自DB的线程和进程及其他进程在访问,然而,这些都没有明确的暴露给你的代码,所以你大可以不必担心来自其他I/O的干扰或相互作用,比方说,并不需要在意像数据库或者别的异步进程这些,因为从请求的角度看来,这些线程的结构都是通过事件轮询返回到你的代码中的,相比起Apache模型,少了许多线程和连接的开销,因为线程不需要遍历每个连接,只有当你必须要使用其他的并行操作等,哪怕这服务器管理是node.js,也阻止不了你

除了I/O调用外,node.js希望所有的请求都能迅速返回,比如说像当cpu快速密集处理一堆请求后,应尽快分离掉这些进程,你可以与事件或是通过使用一个抽象的玩意比如WebWorkers互动,这很显然意味着你无法将你的代码通过事件脱离一个后台的线程独自并行.基本上所有的对象发出事件(比如EventEmitter的实例)都是支持异步事件的互动的,你可以使用这种方式,比如使用文件阻塞代码交互,sockets或是子进程等,这些都是可以在node.js中与事件进行互动的,多核的机子可以使用这些方法,(可以查阅关于Http与Node)

内部实现

在内部,node.js依赖于测试程序提供的时间循环,并辅以libeio采用混合线程来提供异步I/O,想知道更多的话,可以查阅下libev documentation
js内部同样有事件轮询机制

那么我们要怎样在node.js中使用异步?

Tim Caswell描述了这么个模式在这( 网址失效了)

  1. 第一类函数(First-class-functions).我们将函数作为参数传出去,在需要的时候执行他们就可以了
  2. 复合函数(Function composition).也就是所谓的匿名函数或者是当I/O这些事件执行后回调的函数

请求会将所有的事件都放入到队列中,而node.js会不断询问是否有事件,如果存在事件那么便会立即执行,如果执行过程中存在阻塞事件的话,那么node.js会将它放到一个专门的线程池中专门执行这些操作

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

推荐阅读更多精彩内容