Node.js的第一个基本论点是I/O开销很大。

当前编程技术中等待I/O完成会浪费大量的时间。有几种方法可以处理这种性能上的影响:

  • 同步:每次处理一个请求,依次处理。优点:简单;缺点:任何一个请求都可以阻塞所有其他的请求。
  • Fork一个新进程:开一个新进程来处理每个请求。优点:容易;缺点:不能很好的扩展,成百上千个连接意味着成百上千个进程。fork()函数相当于Unix程序员的锤子,因为它很有用,每个问题看起来就像一个钉子,通常会被过度使用。(译者注:直译比较拗口,我理解的意思是,Unix程序员可以用fork()函数解决很多问题)
  • 线程:开一个新线程来处理每个请求。优点:容易,与使用fork相比,对内核更友好,因为线程通常开销较小;缺点:机器可能没有线程,线程编程可以非常复杂非常快,但是必须关注共享资源的权限问题。

第二个基本论点是每个连接开一个线程内存开销很大。

Apache是多线程的:它会为每个请求生成一个线程(或者进程,依据配置文件conf中的配置)。随着并发连接数的增加,你可以看到基本开销如何耗尽内存,需要更多的线程来服务同时在线的客户端。Nginx和Node.js不是多线程的,因为线程和进程会带来很大内存负担。它们是单线程,但是基于事件的。在一个线程中处理多个连接的开销比在成千上万个线程或进程中处理连接的开销小。

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

它真的是单个线程在运行:你不能有任何并行的代码操作;例如模拟一个"sleep"阻塞服务器一秒钟:

var now = new Date().getTime();
while(new Date().getTime() < now + 1000){}

当这段代码执行时,node.js不会响应客户端的任何请求,因为它只有一个线程来执行你的代码。就像你有些CPU正在执行密集型任务,例如缩放图片,它会阻塞所有的其他请求。

……不管怎么样,一切都可以并行,除了你的代码

在一个请求中无法让代码并行。但是所有的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的趋势)(译者注:WTF在此处是What The Fuck的缩写)。

在node.js中,你不应该担心后台发生了什么:当你做I/O操作时,只需要使用回调函数;可以保证你的代码不会被中断,I/O操作不会阻塞其他请求,也无需承担每个请求的线程/进程成本(例如Apache中的内存开销)。

异步I/O操作也有好处,因为I/O操作比大多数代码开销更大,我们应该做一些更好的事情而不仅仅是等待I/O操作。

事件轮询是"一种掌握和处理外部事件并且把它们转成回调调用的实体"。因此I/O调用是一些调用点,node.js可以在这些点从一个请求转换到另一个请求。在一次I/O调用时,你的代码保存回调并且把流程控制权返给node.js的运行环境。当数据可用时,回调方法会被调用。

当然,在后台还是有线程和进程进行数据库访问和流程执行的。但是你的代码不需要显示的接触这些,因此你不必担心它们,只需知道I/O交互就行了。例如从每个请求的角度来看,数据库或其他流程需要异步,因为这些线程的结果通过事件轮询返回给你的代码。与Apache模块相比,因为不需要为每个连接创建线程,可以减少线程和线程开销;只有当你确定有些事情需要并行处理,即使这样也通过node.js来处理这种管理。

除了I/O调用,Node.js希望所有的请求都可以快速的返回;例如CPU密集型任务应该被分离到另一个进程中,然后通过事件进行交互,或者通过使用一个抽象概念像WebWorkers。这(明显的)意味着你不能并行化你的代码,除非后台有另一个线程,你可以通过事件与之交互。基本上所有的能发出事件的对象(例如EventEmitter的实例)都支持异步事件交互,你可以用这种方式与阻塞代码交互,例如正在使用的文件,sockets或者子进程,所有这些都是node.js中的EventEmitters。多核可以使用这种方法;参见node-http-proxy。

内部实现

在内部,node.js依赖libev提供事件轮询,libev依赖libeio,libeio使用线程池来提供异步I/O。想要进一步学习事件,看下libev的文档

那么在node.js中如何做到异步?

  • 一等函数。例如我们把函数作为数据传递,改变它们,需要的时候会执行它们。
  • 复合函数。又称为匿名函数或闭包,在基于事件的I/O中发生某种事件时执行。

(译者注:即第一种是传递定义好的函数,第二种是传递匿名函数)

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

【译】理解node.js事件轮询的更多相关文章

  1. node.js事件轮询(1)

    事件轮询(引用) 事件轮询是node的核心内容.一个系统(或者说一个程序)中必须至少包含一个大的循环结构(我称之为"泵"),它是维持系统持续运行的前提.nodejs中一样包含这样的 ...

  2. [译] 所有你需要知道的关于完全理解 Node.js 事件循环及其度量

    原文地址:All you need to know to really understand the Node.js Event Loop and its Metrics 原文作者:Daniel Kh ...

  3. js事件轮询机制

    console.log(1) setTimeout(function(){ console.log(2) },0); console.log(3) 毫无疑问:运行结果是1 3 2 也就是说:setTi ...

  4. Node.js事件的正确使用方法

    前言 事件驱动的编程变得流行之前,在程序内部进行通信的标准方法非常简单:如果一个组件想要向另外一个发送消息,只是显式地调用了那个组件上的方法.但是在 react 中用的却是事件驱动而不是调用. 事件的 ...

  5. 理解Node.js的事件轮询

    前言 总括 : 原文地址:理解Node.js的事件轮询 Node小应用:Node-sample 智者阅读群书,亦阅历人生 正文 Node.js的两个基本概念 Node.js的第一个基本概念就是I/O操 ...

  6. 对Node.JS的事件轮询(Event Loop)的理解

    title: Node.JS的事件轮询(event loop)的理解 categories: 理解 tags: Node JS 机制 当我们知道I/O操作和创建新线程的开销是巨大的! 网站延迟的开销 ...

  7. Node.js的异步IO和事件轮询

     想象一下,以前我们在写程序时, 如果程序在I/O上阻塞了,当有更多请求过来时,服务器会怎么处理呢?在这种情景中通常会用多线程的方式.一种常见的实现是给每个连接分配一个线程,并为那些连接设置一个线程池 ...

  8. Node.js的事件轮询Event Loop原理

    Node.js的事件轮询Event Loop原理解释 事件轮询主要是针对事件队列进行轮询,事件生产者将事件排队放入队列中,队列另外一端有一个线程称为事件消费者会不断查询队列中是否有事件,如果有事件,就 ...

  9. node.js中的事件轮询Event Loop

    任务队列/事件队列 "任务队列"是一个事件的队列,IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈" ...

随机推荐

  1. UI自动化--PageObjects(页面对象)

    核心的核心:减少了重复代码的数量,减少变更涉及面:做到如果UI发生更改,则只需在一个位置应用此修复程序. PageObject:将页面作为一个对象,进行封装,包括元素定位,封装获取各元素.操作的方法: ...

  2. Git之远程仓库

    1,注册账号 登录https://github.com注册一个账号 2,上传公钥 本地CentOS使用命令 ssh-keygen -t rsa生成秘钥 复制秘钥输入到github网站 3,新建仓库 4 ...

  3. ubuntu16.04下安装pycharm

    下面开始教程 先在PyCharm官网下载安装包 链接:https://www.jetbrains.com/pycharm/download/#section=linux 选择平台为Linux,可以看到 ...

  4. 对position的认知观

    position :absolute 认识以前有的理解不正确,以为没有设置left,top 与设置left :0,top : 0是一样的,现在认识为,错误! 没有设置的时候,该absolute元素{由 ...

  5. Windows hackson (rundll32--ADS)

    http://www.tuicool.com/articles/AnuqA3 http://www.2cto.com/Article/201507/424713.html http://drops.w ...

  6. Spring Boot中的AutoConfiguation核心注解

    import org.springframework.boot.autoconfigure.condition.*; @ConditionalOnBean // 当容器中有指定bean的条件下 @Co ...

  7. Python面试网络编程和并发

    1.简述 OSI 七层协议. OSI 开放系统互联参考模型,它是理论的,参考模型 七层:物理层->数据链路层->网络层->传输层->会话层->表示层->应用层 2. ...

  8. models语言中filter和all取数据有什么区别

    转自:http://www.bubuko.com/infodetail-1882394.html rs=Person.objects.all() all返回的是QuerySet对象,程序并没有真的在数 ...

  9. pandas绘图总结

    转自:http://blog.csdn.net/genome_denovo/article/details/78322628 pandas绘图总结 pandas中的绘图函数(更加详细的绘图资料可参考p ...

  10. 算法抽象及用Python实现具体算法

    一.算法抽象 它们一般是在具体算法的基础上总结.提炼.分析出来的,再反过来用于指导解决其它问题.它们适用于某一类问题的解决,用辩 证法的观点看,抽象的算法和具体的算法就是抽象与具体.普遍性与特殊性.共 ...