了解NodeJS内部执行

时间:2016-12-05 18:39:00

标签: node.js multithreading event-loop

我试图理解幕后发生的事情 如果我尝试执行此NodeJS代码:

http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); response.end('Hello World\n'); }).listen(8081);

我有2个关于上述代码的案例:

1。修改代码在最后一行做一些阻塞 http.createServer回调函数:

http.createServer(function (request, response) {    
    response.writeHead(200, {'Content-Type': 'text/plain'});

    response.end('Hello World\n');

    sleep(2000); //sleep 2 seconds after handling the first request 

}).listen(8081);`


//found this code on the web, to simulate php like sleep function 

function sleep(milliseconds) 
{
   var start = new Date().getTime();
   for (var i = 0; i < 1e7; i++) 
   {
      if ((new Date().getTime() - start) > milliseconds)
      {
          break;
      }
   }
}

我使用这个简单的bash循环向NodeJS服务器发出两个请求

$ for i in {1..2}; do curl http://localhost:1337; done

客户端控制台上的

结果:

Hello world #first iteration

两秒后,下一个hello world将打印在客户端控制台上

Hello world #second iteration

在请求的第一次迭代中,服务器可以立即响应请求。 但是在请求的第二次迭代中,服务器正在阻塞,并在两秒钟后将响应返回给请求。这是因为睡觉 处理第一个请求后阻塞请求的函数。

  1. 修改代码,而不是使用sleep,我在setTimeout回调函数的结束行使用http.createServer

    http.createServer(function (request, response) {    
        response.writeHead(200, {'Content-Type': 'text/plain'});
    
        response.end('Hello World\n');
    
        setTimeout(function(){console.log("Done");}, 2000);
    
     }).listen(8081);`
    
  2. 我再次使用这个简单的bash循环来执行请求

    for i in {1..2}; do curl http://localhost:1337; done

    结果是响应立即返回到两个请求。 并且还会立即在控制台上打印Hello world消息。 这是因为我使用setTimeout函数,它本身就是一个异步函数。

    我对此处发生的事情有疑问:

    1.如果我说:It is the responsibility for the programmer to make asynchronous call in NodeJS code so that the NodeJS internal can continue to execute other code or request without blocking.

    ,我是对的

    2.NodeJS内部使用Google V8 Engine执行javascript代码并使用libuv执行异步操作。

    事件循环负责检查事件队列中是否存在与回调相关的事件,并检查调用堆栈中是否有剩余代码,如果事件队列不为空且调用堆栈为空则从事件回调队列被推送到堆栈,导致回调被执行。

    问题是:

    一个。在NodeJS中执行异步操作时,回调函数的执行是否与NodeJS主线程中代码的执行分开(通过使用libuv线程池)?

    B中。如果有多个连接同时到达服务器,Event Loop如何处理连接?

    我将非常感谢每一个答案,并尝试向他们学习。

2 个答案:

答案 0 :(得分:1)

关于你的一些问题:

  1.   

    程序员负责进行异步调用   在NodeJS代码中,以便NodeJS内部可以继续执行   其他代码或请求没有阻止。

  2. 正确!请注意,可以(如果需要)执行同步阻塞代码。例如,请参阅所有&#39;同步&#39; fs模块的功能,如fs.accessSync

    1.   

      在NodeJS中执行异步操作时,是否执行了回调   函数从执行中分离(通过使用libuv线程池)   NodeJS主线程中的代码

    2. Node.js是单线程的,所以没有主线程&#39;。触发时,回调函数的执行是唯一执行的代码。 node.js的异步设计是由事件循环&#39;完成的。如你所说

      1.   

        如果有多个,事件循环如何处理连接   连接同时到达服务器?

      2. 没有相同的时间&#39;真。一个是第一个,其余的正在排队。假设你没有阻止代码,他们应该快速处理(你可以并且应该加载测试你的服务器,看看有多快)

答案 1 :(得分:0)

首先,我不知道睡眠是做什么的。

基本上,事件循环会检查哪些资源是免费的,以及排队事件的需求(如果有的话)。当您致电setTimeout时,它会在2秒后执行console.log("Done")。您是否对其进行了编程以停止该功能的整体执行? 即可。在发送响应后,您只要求特定请求执行某些操作。您没有要求停止函数执行或阻止事件。您可以阅读有关线程here的更多信息。该程序本身是异步的。

现在,如果你想让它同步,你需要自己的事件循环。你能在setTimeout中采取所有行动。

setTimeout(function() {
    response.end('Hello World\n');
    response.writeHead(200, {'Content-Type': 'text/plain'});
    console.log("Done");
}, 2000);

您是否仍然拒绝其他请求停止执行? 即可。如果你同时发出2个请求,你将在2秒后同时得到2个响应。

让我们更深入,更多地控制请求。假设有两个全局变量counter = 0和current_counter = 0.它们位于http.create...之外。一旦请求到来,我们就为它分配一个计数器并执行它。然后我们等待2秒,然后递增计数器并执行下一个请求。

counter = 0;
current_counter = 0;
http.createServer(function (request, response) {
    var my_count = counter; // my_count specific to each request, not common, not global
    counter += 1;

    while(current_counter <= my_count)
        if (current_counter == my_count) {
            setTimeout(function() {
                response.end('Hello World\n');
                response.writeHead(200, {'Content-Type': 'text/plain'});
                console.log("Done");
                return current_counter += 1;
            }, 2000);
        }
    }
}).listen(8081);`

尝试了解我的所作所为。我以while循环的形式创建了自己的事件循环。它监听current_counter等于my_count的条件。想象一下,3个请求进入的时间少于2秒。请记住,我们仅在2秒后增加current_counter。

请求时间不到2秒

  1. A - current_counter = 0,my_count = 0 - &gt;在执行中,将在2秒后发送响应。
  2. B - current_counter = 0(仅在2秒后递增),my_count = 1 - &gt;卡在while循环条件下。等待current_counter等于1执行。
  3. C - current_counter = 0,my_count = 2 - &gt;像之前的请求一样停留在while循环中。
  4. 2秒后,请求A由setTimeout响应。变量current_count变为1,请求B的局部变量my_count等于它并执行setTimeout。因此,发送对请求B的响应并且在2秒之后递增current_counter,这导致执行请求C等等。

    您可以将尽可能多的请求排队,但由于我自己的事件循环检查条件,而后者依赖于仅在2秒后执行的setTimeout,因此仅在2秒后执行。

    谢谢!