我正在尝试简单的NodeJS应用程序,以便我能够理解异步性质。
但我的问题是,一旦我从浏览器点击“/home
”它等待响应,同时当“/
”被点击时,它会等待“/home
”先响应,然后回复“/
”请求。
我担心的是,如果其中一个请求需要大量处理,我们不能同时请求另一个请求?这是对的吗?
app.get("/", function(request, response) {
console.log("/ invoked");
response.writeHead(200, {'Content-Type' : 'text/plain'});
response.write('Logged in! Welcome!');
response.end();
});
app.get("/home", function(request, response) {
console.log("/home invoked");
var obj = {
"fname" : "Dead",
"lname" : "Pool"
}
for (var i = 0; i < 999999999; i++) {
for (var i = 0; i < 2; i++) {
// BS
};
};
response.writeHead(200, {'Content-Type' : 'application/json'});
response.write(JSON.stringify(obj));
response.end();
});
答案 0 :(得分:2)
好问题, 现在,尽管Node.js具有异步特性,但这段代码:
for (var i = 0; i < 999999999; i++) {
for (var i = 0; i < 2; i++) {
// BS
};
};
非异步实际上阻塞了节点主线程。因此,所有其他请求必须等到这个大的for
循环结束。
为了同时进行一些繁重的计算,我建议您使用setTimeout
或setInterval
来实现目标:
var i=0;
var interval = setInterval(function() {
if(i++>=999999999){
clearInterval(interval);
}
//do stuff here
},5);
有关详细信息,我建议搜索&#34; Node.js事件循环&#34;
答案 1 :(得分:0)
作为Stasel,stated,运行的代码将阻止事件循环。基本上每当javascript在服务器上运行时,没有其他任何东西在运行。磁盘I / O等异步I / O事件可能在后台处理,但除非同步代码已完成运行,否则不会调用它们的处理程序/回调。基本上,一旦完成,节点将检查要处理的待处理事件并分别调用它们的处理程序。
你实际上有几个选择来解决这个问题。
分解工作并让待处理事件在两者之间执行。这与Stasel的建议几乎相同,只是单次迭代之间的5ms是巨大的。对于像999999999这样的东西,这需要永远。首先,我建议批量处理循环一段时间,然后使用setimmediate
安排下一批处理。 setimmediate
基本上会在处理挂起的I / O事件后安排它,所以如果没有新的I / O事件要处理(比如没有新的http请求),那么它将立即执行。它足够快。现在问题是我们应该为每个批次/迭代做多少处理。我建议首先手动测量它的平均值,以及约50ms的工作时间表。例如,如果您已经意识到1000件物品需要100毫秒。然后让它处理500个项目,所以它将是50ms。你可以进一步细分,但分解越多,总共需要的时间就越多。所以要小心。此外,由于您正在处理大量物品,请尽量不要制造太多垃圾,因此垃圾收集器不会阻止它。在this not-so-similar question中,我已经解释了如何在不阻塞事件循环的情况下将10000个文档插入MongoDB。
使用线程。实际上有一些很好的线程实现,你不会与他们一起拍摄。对于这种情况来说,这确实是一个好主意,如果你正在寻找大型处理的性能,因为如上所述,实现CPU绑定任务与同一过程中发生的其他事情很好地相处会很棘手,异步事件非常适合数据绑定任务不是CPU绑定任务。您可以使用nodejs-threads-a-gogo模块。您还可以使用基于threads-a-gogo构建的node-webworker-threads,但使用webworker API。还有nPool,看起来更漂亮但不太受欢迎。它们都支持线程池,应该直接实现工作队列。
制作多个进程而不是线程。这可能比线程慢,但对于巨大的东西,仍然比在主进程中迭代更好。有不同的方式。使用进程将为您带来一种设计,您可以将其扩展为使用多台计算机而不是仅使用多个CPU。您可以使用作业队列(基本上在完成要处理的任务时从队列中拉出下一个),多进程map-reduce或AWS弹性映射reduce,或使用nodejs集群模块。使用群集模块,您可以在每个worker上侦听unix域套接字,并且每个作业只需向该套接字发出请求。只要工作人员完成处理作业,它就会回写该特定请求。您可以搜索这些内容,已经存在许多实现和模块。您可以使用0MQ,rabbitMQ,节点内置ipc,unix域套接字或redis队列进行多进程通信。