了解 NodeJS 内部执行
Understanding The NodeJS Internal execution
我正在尝试了解引擎盖下发生的事情
如果我尝试执行此 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
#第一次迭代
两秒后,下一个 hello world 打印在客户端控制台上
Hello world
#第二次迭代
在请求的第一次迭代中,服务器可以立即响应请求。
但是在请求的第二次迭代中,服务器处于阻塞状态,return 两秒后对请求的响应。这是因为睡眠
在处理第一个请求后阻止请求的函数。
修改代码,我在http.createServer
回调函数的最后一行使用setTimeout
代替睡眠
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);`
我再次使用这个简单的 bash 循环来执行请求
for i in {1..2}; do curl http://localhost:1337; done
结果是 return 立即对两个请求进行了响应。
Hello world
消息也会立即打印在控制台上。
这是因为我使用的是 setTimeout
函数,它本身就是一个异步函数。
我对这里发生的事情有疑问:
1.Am 我说对了: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.The NodeJS 内部 使用 Google V8 Engine
执行 javascript 代码并使用 libuv
执行异步操作。
Event Loop负责检查事件队列中是否有任何与回调相关的事件发生,并检查调用堆栈中是否有剩余代码,如果事件队列不为空且调用堆栈为空则回调来自事件队列的被推入堆栈,导致回调被执行。
问题是:
一个。在 NodeJS 中执行异步操作时,回调函数的执行是否与 NodeJS 主线程中的代码执行分开(通过使用 libuv
线程池)?
乙。如果有多个连接同时到达服务器,Event Loop
如何处理连接?
我会非常感谢每一个答案,并努力从中学习。
关于您的几个问题:
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.
正确!请注意,可以(如果需要)执行同步阻塞代码。例如,查看 fs 模块的所有 'Sync' 函数,如 fs.accessSync
When doing Async thing in NodeJS, Is that execution of callback
function is separated (by using libuv thread pool) from the execution
of the code in NodeJS main thread
Node.js是单线程,所以没有'main thread'。触发时,回调函数的执行是唯一被执行的代码。 node.js的异步设计是由'Event Loop'完成的,如你所说
How The Event Loop handle the connections if there is multiple
connection arrive at the same time to the server?
真的没有'same time'。一个先到,其余的在排队。假设你没有阻塞代码,它们应该被快速处理(你可以而且应该对你的服务器进行负载测试,看看到底有多快)
首先,我不知道sleep是干什么的
基本上,事件循环会检查哪些资源是空闲的,以及排队事件的需求是什么(如果有的话)。当您调用 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 的条件。想象一下,在不到 2 秒的时间内收到 3 个请求。请记住,我们仅在 2 秒后递增 current_counter。
不到 2 秒的请求
- A - current_counter = 0, my_count = 0 -> 执行中,将在 2 秒后发送响应。
- B - current_counter = 0(仅在 2 秒后递增),my_count = 1 -> 卡在 while 循环条件中。等待 current_counter 等于 1 执行。
- C - current_counter = 0,my_count = 2 -> 像之前的请求一样陷入 while 循环。
2秒后,请求A通过setTimeout响应。变量current_count变为1,请求B的局部变量my_count等于它,执行setTimeout。因此,发送对请求 B 的响应,并且 current_counter 在 2 秒后递增,这导致执行请求 C,依此类推。
您可以对尽可能多的请求进行排队,但执行仅在 2 秒后发生,因为我自己的事件循环会检查条件,而这又取决于仅在 2 秒后执行的 setTimeout。
谢谢!
我正在尝试了解引擎盖下发生的事情 如果我尝试执行此 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
#第一次迭代
两秒后,下一个 hello world 打印在客户端控制台上
Hello world
#第二次迭代
在请求的第一次迭代中,服务器可以立即响应请求。 但是在请求的第二次迭代中,服务器处于阻塞状态,return 两秒后对请求的响应。这是因为睡眠 在处理第一个请求后阻止请求的函数。
修改代码,我在
http.createServer
回调函数的最后一行使用setTimeout
代替睡眠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);`
我再次使用这个简单的 bash 循环来执行请求
for i in {1..2}; do curl http://localhost:1337; done
结果是 return 立即对两个请求进行了响应。
Hello world
消息也会立即打印在控制台上。
这是因为我使用的是 setTimeout
函数,它本身就是一个异步函数。
我对这里发生的事情有疑问:
1.Am 我说对了: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.The NodeJS 内部 使用 Google V8 Engine
执行 javascript 代码并使用 libuv
执行异步操作。
Event Loop负责检查事件队列中是否有任何与回调相关的事件发生,并检查调用堆栈中是否有剩余代码,如果事件队列不为空且调用堆栈为空则回调来自事件队列的被推入堆栈,导致回调被执行。
问题是:
一个。在 NodeJS 中执行异步操作时,回调函数的执行是否与 NodeJS 主线程中的代码执行分开(通过使用 libuv
线程池)?
乙。如果有多个连接同时到达服务器,Event Loop
如何处理连接?
我会非常感谢每一个答案,并努力从中学习。
关于您的几个问题:
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.
正确!请注意,可以(如果需要)执行同步阻塞代码。例如,查看 fs 模块的所有 'Sync' 函数,如 fs.accessSync
When doing Async thing in NodeJS, Is that execution of callback function is separated (by using libuv thread pool) from the execution of the code in NodeJS main thread
Node.js是单线程,所以没有'main thread'。触发时,回调函数的执行是唯一被执行的代码。 node.js的异步设计是由'Event Loop'完成的,如你所说
How The Event Loop handle the connections if there is multiple connection arrive at the same time to the server?
真的没有'same time'。一个先到,其余的在排队。假设你没有阻塞代码,它们应该被快速处理(你可以而且应该对你的服务器进行负载测试,看看到底有多快)
首先,我不知道sleep是干什么的
基本上,事件循环会检查哪些资源是空闲的,以及排队事件的需求是什么(如果有的话)。当您调用 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 的条件。想象一下,在不到 2 秒的时间内收到 3 个请求。请记住,我们仅在 2 秒后递增 current_counter。
不到 2 秒的请求
- A - current_counter = 0, my_count = 0 -> 执行中,将在 2 秒后发送响应。
- B - current_counter = 0(仅在 2 秒后递增),my_count = 1 -> 卡在 while 循环条件中。等待 current_counter 等于 1 执行。
- C - current_counter = 0,my_count = 2 -> 像之前的请求一样陷入 while 循环。
2秒后,请求A通过setTimeout响应。变量current_count变为1,请求B的局部变量my_count等于它,执行setTimeout。因此,发送对请求 B 的响应,并且 current_counter 在 2 秒后递增,这导致执行请求 C,依此类推。
您可以对尽可能多的请求进行排队,但执行仅在 2 秒后发生,因为我自己的事件循环会检查条件,而这又取决于仅在 2 秒后执行的 setTimeout。
谢谢!