回调中的for循环。阻塞?

Igo*_*kić 5 mongoose node.js

//defining schemas, models, db connections, etc..

http.createServer(function (req, res) {
  // some irrelevant stuff..

  Model.find({name : regex}).exec(function (err, results) {  

    var localArray = []; 

    for (var i = 0, len = results.length; i < len; ++i) {
      localArray.push(results[i].name);
      localArray.push(results[i].id);
    };  // is this for loop blocking?

  // some more irrelevant stuff..
  });
}).listen(8080);
Run Code Online (Sandbox Code Playgroud)

我的回调有一个 for 循环,它可能很长(有时 results.length = 100)。

我写了阻塞代码吗?如果是,我怎样才能让它不阻塞?

Eug*_*kov 6

长话短说,答案是肯定的,它是阻塞。您在此循环运行时收到的任何请求都将排队。使用子进程解锁您的父代码。它要求你的机器是多核的(不是为了产生一个进程而是为了高效)。

长长的故事:

JavaScript(因此 Node)是单线程的。在这个问题的上下文中它意味着什么 - 当你的循环运行时,不能调用其他函数。解除阻塞的唯一方法是使用子进程。你有两种选择,每种都有自己的优势和缺点。

  1. 运行一个集群,这样当一个节点进程被“阻塞”时,你就有另一个进程来处理传入的请求。
  2. 生成一个子进程来为您运行一些繁重的工作,然后返回结果。

第一个选项非常简单,需要您将服务器包装在集群中http://nodejs.org/api/cluster.html 然而,您可能会“阻止”整个集群,并在每个节点进程中运行此循环。

第二种选择实施起来更复杂,需要更多的资源。但是当你必须做一些非常繁重和/或可能会导致内存泄漏的事情时,这真是太棒了。这允许你做的是创建一个单独的 Node 进程(这将需要一些 RAM 并需要一些毫秒才能启动,所以你不能产生数百万个这样的人),向它传递一些参数并等待结果到来。您的父进程将能够为即将到来的请求提供服务。但是不要忘记在完成后杀死子进程。 http://nodejs.org/api/child_process.html

无论您选择什么,请注意您仍然在同一台机器上运行,您遇到的下一个瓶颈是您的机器资源。无论如何运行一些基准测试。迭代一百多个项目并不会产生一个孩子那么重,但是如果你迭代数千个或更多?...

ps 反向循环运行得更快:

for (var i = results.length; i > 0; i--) {
  //Do something
};  
Run Code Online (Sandbox Code Playgroud)