Node.js中的单线程和事件循环

时间:2013-07-10 20:13:01

标签: node.js event-loop

首先,我是初学者,试图了解什么是Node.Js.我有两个问题。

第一个问题
来自Felix的the article,它说“同时只能有一个回调触发。在回调完成执行之前,所有其他回调都必须排队等待。”

然后,考虑以下代码(从nodejs官方网站复制)

var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8124, "127.0.0.1");

如果同时收到两个客户端请求,则表示以下工作流程:

  1. 收到第一个http请求事件,收到第二个请求事件。
  2. 收到第一个事件后,第一个事件的回调函数正在执行。
  3. 同时,第二个事件的回调函数必须等待。
  4. 我是对的吗?如果我是对的, Node.js 如何控制在非常短的时间内是否有数千个客户端请求。

    第二个问题
    术语“事件循环”主要用于Node.js主题。我已将“事件循环”理解为http://www.wisegeek.com/what-is-an-event-loop.htm;

    中的以下内容
      

    事件循环 - 或主循环,是程序中的构造   控制和调度初始事件后的事件。

         

    最初的事件可以是任何事情,包括按下按钮   键盘或单击程序上的按钮(在Node.js中,我认为   初始事件将是http请求,数据库查询或I / O文件访问)。

         

    这称为循环,不是因为事件圈出而发生   不断,但因为循环准备一个事件,检查   事件,调度事件并重新重复该过程。

    我对第二段有冲突,特别是短语“重复这个过程”。我接受上面的问题上面的 http.createServer 代码绝对是“事件循环”,因为它反复监听http请求事件。

    但我不知道如何识别以下代码,无论是事件驱动还是事件循环。除了在db查询完成后触发的回调函数之外,它不会重复任何操作。

    database.query("SELECT * FROM table", function(rows) {
      var result = rows;
    });
    

    请让我听听你的意见和答案。

2 个答案:

答案 0 :(得分:8)

回答一个,你的逻辑是正确的:第二个事件会等待。并且会在排队的回调时间到来之前执行。

同样,请记住技术世界中没有“同时”这样的东西。一切都有非常具体的地点和时间。

node.js管理数千个连接的方式是,在有一些数据库调用阻塞逻辑或者正在处理另一个IO操作(例如流)时,不需要保持线程空闲。它可以“服务”第一个请求,可能会创建更多回调,然后继续进行其他请求 因为没有办法阻止执行(除了废话(真实)和类似),它在整个应用程序逻辑中传播实际资源变得非常有效。

线程 - 价格昂贵,线程的服务器容量与可用内存直接相关。因此,大多数经典Web应用程序都会受到影响,因为在数据库查询块正在进行或类似的情况下,RAM用于简单空闲的线程。在节点中并非如此。

但是,它允许通过cluster创建多个线程(作为child_process),这扩展了更多的可能性。

回答两个。没有你想到的“循环”这样的东西。幕后没有循环可以检查是否有连接或接收到任何数据等等。现在它也是由Async方法处理的。

所以从应用程序的角度来看,没有'主循环',从开发人员的角度来看,一切都是事件驱动的(不是事件循环)。

如果使用http.createServer,则将回调绑定为对请求的响应。所有套接字操作和IO内容都将在幕后发生,以及HTTP握手,解析标头,查询,参数等。一旦它在幕后发生并且工作完成,它将保留数据并将回调推送到具有一些数据的事件循环。一旦事件循环生效,并且将会在node.js应用程序上下文中执行你的回调,其中包含来自幕后的数据。

有了数据库请求 - 同样的故事。它不准备并询问内容(可能会再次执行异步),然后在数据库响应并将为应用程序上下文准备数据时进行回调。

说实话,node.js所需要的只是理解概念,而不是事件的实现。 最好的方法 - 实验。

答案 1 :(得分:1)

1)是的,你是对的。

它的工作原理是因为您对节点所做的一切主要是I / O绑定。

当新请求(事件)进入时,它会被放入队列中。在初始化时,Node分配一个ThreadPool,负责为I / O绑定处理产生线程,如网络/套接字调用,数据库等(这是非阻塞的)。

现在,你的"回调" (或事件处理程序)非常快,因为您正在做的大多数事情很可能是CRUD和I / O操作,而不是CPU密集型操作。

因此,这些回调让人感觉它们是并行处理的,但它们实际上并非如此,因为实际的并行工作是通过ThreadPool(具有多线程)完成的,而回调本身只是从这些线程接收结果,以便处理可以继续并将响应发送回客户端。

您可以轻松验证这一点:如果您的回调是 CPU任务,您可以确定您无法每秒处理数千个请求,并且它的缩小非常糟糕,相比之下一个多线程系统。

2)你是对的。

不幸的是,由于所有这些抽象,你必须潜水才能了解后台发生了什么。但是,是的,有一个循环。

特别是,Nodejs是用libuv实现的。

read感兴趣。

  

但我不知道如何识别以下代码,无论是事件驱动还是事件循环。除了在db查询完成后触发的回调函数之外,它不会重复任何操作。

事件驱动是您通常在有事件循环时使用的术语,它表示由点击按钮,数据到达等事件驱动的应用程序。通常,您将回调关联到这样的事件。