在Node.js中,setTimeout()会阻塞事件循环吗?

时间:2021-07-17 23:57:49

If I have a simple setTimeout() function, and set it for 10 seconds...

如果我有一个简单的setTimeout()函数,并将其设置为10秒......

The the entire server is dead inside those 10 seconds??? Is this true? That's what I heard.

整个服务器在那10秒钟内死了???这是真的?这就是我所听到的。

5 个解决方案

#1


20  

The answer is no. What your link Node.js: How would you recreate the 'setTimeout' function without it blocking the event loop? showed was not a setTimeout blocking the event loop it was a while loop that deliberately blocks the event loop. If you want your server to be fast you do not want to block the event loop. An asynchronous callback such as setTimeout will work great.

答案是不。您的链接Node.js:如果不阻止事件循环,您将如何重新创建'setTimeout'函数?显示不是阻塞事件循环的setTimeout它是故意阻止事件循环的while循环。如果您希望服务器速度很快,则不希望阻止事件循环。像setTimeout这样的异步回调效果很好。

Are you trying to block for some reason (like testing or something?)

你是否因某种原因试图阻止(比如测试什么?)

#2


5  

Another finding that may help others who are learning Node.js and curious of this question, but tricked by a hidden behavior of modern browsers.

另一个发现可能有助于其他正在学习Node.js并对这个问题充满好奇的人,但却被现代浏览器的隐藏行为所欺骗。

The code is really simple, I just want to test my understanding of the "async nature" of Node.js.

代码非常简单,我只想测试我对Node.js的“异步性”的理解。

var express = require('express');
var router = express.Router();

router.get('/', function(req, res, next) {
    console.log("route begin");
    var start = new Date();


    setTimeout(function() {
        res.render('index', { title: start + ' - ' + new Date()});
    }, 20000);//force delay of 20 seconds.

    console.log("route end");
});

module.exports = router;

If I start three browser windows(Firefox, more accurately), open the URL defined by this route at the same time, and check the console log from Node.js, it is clear the request is not handled concurrently!

如果我启动三个浏览器窗口(Firefox,更准确),同时打开此路由定义的URL,并从Node.js检查控制台日志,很明显请求不会同时处理!

I tried the test several times, the results are same.

我试了好几次,结果是一样的。

The typical log output is like this:

典型的日志输出如下:

route begin at: Fri Aug 28 2015 18:35:57 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:35:57 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:36:18 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:36:18 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:36:20 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:36:20 GMT+0800 (CST)

And also, strangely, it was not running in serial mode either(if Node.js is blocked by setTimeout, it should). The interval between the first and second request is 20 seconds, but the second and the third is just 2 seconds.

而且,奇怪的是,它也没有以串行模式运行(如果Node.js被setTimeout阻止,它应该)。第一个和第二个请求之间的间隔是20秒,但第二个和第三个请求之间的间隔仅为2秒。

After scratching my head for quite a while, I suddenly recall that the browser has a connection limit on the same host!

在我挠了头很长一段时间之后,我突然想起浏览器在同一主机上有连接限制!

So, I quickly setup another test, but this time by issuing multiple curl commands instead.

所以,我快速设置另一个测试,但这次通过发出多个curl命令。

Hallelujah!

route begin at: Fri Aug 28 2015 18:42:51 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:42:51 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:42:53 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:42:53 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:42:55 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:42:55 GMT+0800 (CST)

#3


2  

The link which you seem to be confused about does not state that setTimeout will block. Rather, the OP in that question was trying to make a custom function called wait that would behave like setTimeout. The wait function is the blocking function - setTimeout will not block.

您似乎混淆的链接并未声明setTimeout将阻止。相反,该问题中的OP试图创建一个名为wait的自定义函数,其行为类似于setTimeout。 wait函数是阻塞函数 - setTimeout不会阻塞。

#4


2  

That is not true. When you call setTimeout and return out of your code the server is not blocked. It is free to process other events (possibly other setTimeout callbacks) while waiting for your particular timer to fire

事实并非如此。当您调用setTimeout并返回代码时,服务器不会被阻止。在等待特定计时器触发时,可以*处理其他事件(可能是其他setTimeout回调)

#5


0  

The main process seems to be monothreaded by host and blocked by a setTimeout or a while.

主进程似乎被主机单线化并被setTimeout或while阻塞。

However, there is an alternative with this code which works as expected and don't block the main process or the event loop:

但是,有一个替代方法,此代码按预期工作,不会阻止主进程或事件循环:

var express = require('express')
var app = express()

function setTimeoutAsync (callback, time) {
  setTimeout(function () {
    callback()
  }, time)
  return 0
}

app.get('/', function (req, res, next) {
    console.log("route begin")
    var start = +new Date()
    setTimeoutAsync(function () {
      console.log("route done")
      res.json({ delay: ((+new Date()) - start) + 'ms' })
    }, 5000)
    console.log("route end")
});

app.listen(8000) 

In terminal :

在终端:

route begin // first page
route end
route begin // second page
route end
route begin // third page
route end
route done // first render
route done // second render
route done // third render

Good sources:

https://www.journaldev.com/7462/node-js-architecture-single-threaded-event-loop

https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/

#1


20  

The answer is no. What your link Node.js: How would you recreate the 'setTimeout' function without it blocking the event loop? showed was not a setTimeout blocking the event loop it was a while loop that deliberately blocks the event loop. If you want your server to be fast you do not want to block the event loop. An asynchronous callback such as setTimeout will work great.

答案是不。您的链接Node.js:如果不阻止事件循环,您将如何重新创建'setTimeout'函数?显示不是阻塞事件循环的setTimeout它是故意阻止事件循环的while循环。如果您希望服务器速度很快,则不希望阻止事件循环。像setTimeout这样的异步回调效果很好。

Are you trying to block for some reason (like testing or something?)

你是否因某种原因试图阻止(比如测试什么?)

#2


5  

Another finding that may help others who are learning Node.js and curious of this question, but tricked by a hidden behavior of modern browsers.

另一个发现可能有助于其他正在学习Node.js并对这个问题充满好奇的人,但却被现代浏览器的隐藏行为所欺骗。

The code is really simple, I just want to test my understanding of the "async nature" of Node.js.

代码非常简单,我只想测试我对Node.js的“异步性”的理解。

var express = require('express');
var router = express.Router();

router.get('/', function(req, res, next) {
    console.log("route begin");
    var start = new Date();


    setTimeout(function() {
        res.render('index', { title: start + ' - ' + new Date()});
    }, 20000);//force delay of 20 seconds.

    console.log("route end");
});

module.exports = router;

If I start three browser windows(Firefox, more accurately), open the URL defined by this route at the same time, and check the console log from Node.js, it is clear the request is not handled concurrently!

如果我启动三个浏览器窗口(Firefox,更准确),同时打开此路由定义的URL,并从Node.js检查控制台日志,很明显请求不会同时处理!

I tried the test several times, the results are same.

我试了好几次,结果是一样的。

The typical log output is like this:

典型的日志输出如下:

route begin at: Fri Aug 28 2015 18:35:57 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:35:57 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:36:18 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:36:18 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:36:20 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:36:20 GMT+0800 (CST)

And also, strangely, it was not running in serial mode either(if Node.js is blocked by setTimeout, it should). The interval between the first and second request is 20 seconds, but the second and the third is just 2 seconds.

而且,奇怪的是,它也没有以串行模式运行(如果Node.js被setTimeout阻止,它应该)。第一个和第二个请求之间的间隔是20秒,但第二个和第三个请求之间的间隔仅为2秒。

After scratching my head for quite a while, I suddenly recall that the browser has a connection limit on the same host!

在我挠了头很长一段时间之后,我突然想起浏览器在同一主机上有连接限制!

So, I quickly setup another test, but this time by issuing multiple curl commands instead.

所以,我快速设置另一个测试,但这次通过发出多个curl命令。

Hallelujah!

route begin at: Fri Aug 28 2015 18:42:51 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:42:51 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:42:53 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:42:53 GMT+0800 (CST)
route begin at: Fri Aug 28 2015 18:42:55 GMT+0800 (CST)
route end at: Fri Aug 28 2015 18:42:55 GMT+0800 (CST)

#3


2  

The link which you seem to be confused about does not state that setTimeout will block. Rather, the OP in that question was trying to make a custom function called wait that would behave like setTimeout. The wait function is the blocking function - setTimeout will not block.

您似乎混淆的链接并未声明setTimeout将阻止。相反,该问题中的OP试图创建一个名为wait的自定义函数,其行为类似于setTimeout。 wait函数是阻塞函数 - setTimeout不会阻塞。

#4


2  

That is not true. When you call setTimeout and return out of your code the server is not blocked. It is free to process other events (possibly other setTimeout callbacks) while waiting for your particular timer to fire

事实并非如此。当您调用setTimeout并返回代码时,服务器不会被阻止。在等待特定计时器触发时,可以*处理其他事件(可能是其他setTimeout回调)

#5


0  

The main process seems to be monothreaded by host and blocked by a setTimeout or a while.

主进程似乎被主机单线化并被setTimeout或while阻塞。

However, there is an alternative with this code which works as expected and don't block the main process or the event loop:

但是,有一个替代方法,此代码按预期工作,不会阻止主进程或事件循环:

var express = require('express')
var app = express()

function setTimeoutAsync (callback, time) {
  setTimeout(function () {
    callback()
  }, time)
  return 0
}

app.get('/', function (req, res, next) {
    console.log("route begin")
    var start = +new Date()
    setTimeoutAsync(function () {
      console.log("route done")
      res.json({ delay: ((+new Date()) - start) + 'ms' })
    }, 5000)
    console.log("route end")
});

app.listen(8000) 

In terminal :

在终端:

route begin // first page
route end
route begin // second page
route end
route begin // third page
route end
route done // first render
route done // second render
route done // third render

Good sources:

https://www.journaldev.com/7462/node-js-architecture-single-threaded-event-loop

https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/