同时调用setTimeout会导致比预期更多的延迟

我正在做一个Node性能的小演示,很惊讶地发现下面的例子中,有50个setTimeout并发调用需要4秒而不是500ms。

下面的代码设置了一个非常简单的express服务器,它侦听所有请求,并在稍后使用setTimeout来响应500ms。 然后它有一个客户端,通过传递50个请求来跟踪请求和相应的响应。

 // SERVER var express = require('express'); var app = express(); app.get('*', function (req, res) { setTimeout(function () { return res.send(req.query.i); }, 500); }); app.listen(8099); // CLIENT var http = require('http'); function start() { for (var i = 0; i < 50; i++) { console.log(new Date().getSeconds() + ':' + new Date().getMilliseconds() + ' - Sending ' + i); http.get('http://localhost:8099?i=' + i, responseHandler); } function responseHandler(res) { res.on('data', function (body) { return console.log(new Date().getSeconds() + ':' + new Date().getMilliseconds() + ' - Received ' + body); }); } } start(); 

我希望代码需要30-50ms才能完成所有setTimeout调用,然后在500ms之后,所有这些代码都会在同一时间响应。 相反,我看到他们以5人一组来回答,每组5人之间有500毫秒。

我尝试了一些更简单的替代方法,它们都可以解决这个问题。 如果我拿setTimeout并立即回应,所有的50个回应在100ms内进来。 如果我把Web服务器排除在外,并且只有50个setTimeout调用,那么所有的50个调用都会立即排队,所有的50个调用在500ms之后同时返回。

当express和http调用与setTimeout结合使用时,可能会导致额外的延迟?

这个问题与setTimeout没有任何关系(因为您可能已经猜到了当你没有客户端/服务器设置的情况下运行你的testing)。 问题是Node http服务器在任何给定时间处理的开放HTTP套接字的数量。

控制此设置的设置是Agent.maxSockets (有关更多信息,请参阅文档 )。

maxSockets的默认值是五。 所以,如果你发送50个请求到你的应用程序,它将一次处理5个请求, 直到它们完成,然后再转到新的请求。 因为在setTimeout函数调用它们的callback函数之前它们不能完成,所以你的请求会以大约每500毫秒5次的突发速度响应。

如果你想certificate这一点,你所要做的就是改变maxSockets的值:

 http.globalAgent.maxSockets = 10; 

现在,您将看到请求以10个连发处理。 如果将其设置为50,则应该看到您要查找的行为。

请注意,它可能设置为5的一个很好的理由,所以我不认为你的问题的“解决scheme”只是将maxSockets设置为Infinity或类似的东西。

mscdex在注释中指出你可以在http.request指定一个cusotm代理,并且在Node v0.12中将会改变默认的maxSockets。