NodeJS中不同路径的并行请求:长时间运行路径1阻塞其他路径

时间:2014-05-18 07:50:42

标签: node.js

我正在尝试简单的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();
    });

2 个答案:

答案 0 :(得分:2)

好问题, 现在,尽管Node.js具有异步特性,但这段代码:

for (var i = 0; i < 999999999; i++) {
    for (var i = 0; i < 2; i++) {
        // BS
    };  
};

非异步实际上阻塞了节点主线程。因此,所有其他请求必须等到这个大的for循环结束。

为了同时进行一些繁重的计算,我建议您使用setTimeoutsetInterval来实现目标:

var i=0;
var interval = setInterval(function() {
   if(i++>=999999999){
       clearInterval(interval);
   }
   //do stuff here
},5);

有关详细信息,我建议搜索&#34; Node.js事件循环&#34;

答案 1 :(得分:0)

作为Staselstated,运行的代码将阻止事件循环。基本上每当javascript在服务器上运行时,没有其他任何东西在运行。磁盘I / O等异步I / O事件可能在后台处理,但除非同步代码已完成运行,否则不会调用它们的处理程序/回调。基本上,一旦完成,节点将检查要处理的待处理事件并分别调用它们的处理程序。

你实际上有几个选择来解决这个问题。

  1. 分解工作并让待处理事件在两者之间执行。这与Stasel的建议几乎相同,只是单次迭代之间的5ms是巨大的。对于像999999999这样的东西,这需要永远。首先,我建议批量处理循环一段时间,然后使用setimmediate安排下一批处理。 setimmediate基本上会在处理挂起的I / O事件后安排它,所以如果没有新的I / O事件要处理(比如没有新的http请求),那么它将立即执行。它足够快。现在问题是我们应该为每个批次/迭代做多少处理。我建议首先手动测量它的平均值,以及约50ms的工作时间表。例如,如果您已经意识到1000件物品需要100毫秒。然后让它处理500个项目,所以它将是50ms。你可以进一步细分,但分解越多,总共需要的时间就越多。所以要小心。此外,由于您正在处理大量物品,请尽量不要制造太多垃圾,因此垃圾收集器不会阻止它。在this not-so-similar question中,我已经解释了如何在不阻塞事件循环的情况下将10000个文档插入MongoDB。

  2. 使用线程。实际上有一些很好的线程实现,你不会与他们一起拍摄。对于这种情况来说,这确实是一个好主意,如果你正在寻找大型处理的性能,因为如上所述,实现CPU绑定任务与同一过程中发生的其他事情很好地相处会很棘手,异步事件非常适合数据绑定任务不是CPU绑定任务。您可以使用nodejs-threads-a-gogo模块。您还可以使用基于threads-a-gogo构建的node-webworker-threads,但使用webworker API。还有nPool,看起来更漂亮但不太受欢迎。它们都支持线程池,应该直接实现工作队列。

  3. 制作多个进程而不是线程。这可能比线程慢,但对于巨大的东西,仍然比在主进程中迭代更好。有不同的方式。使用进程将为您带来一种设计,您可以将其扩展为使用多台计算机而不是仅使用多个CPU。您可以使用作业队列(基本上在完成要处理的任务时从队列中拉出下一个),多进程map-reduce或AWS弹性映射reduce,或使用nodejs集群模块。使用群集模块,您可以在每个worker上侦听unix域套接字,并且每个作业只需向该套接字发出请求。只要工作人员完成处理作业,它就会回写该特定请求。您可以搜索这些内容,已经存在许多实现和模块。您可以使用0MQ,rabbitMQ,节点内置ipc,unix域套接字或redis队列进行多进程通信。