NodeJS - Memory/CPU 使用 MongoJS Stream 进行管理

NodeJS - Memory/CPU management with MongoJS Stream

我正在解析来自 MongoDB 的一个相当大的数据集(大约 40,000 个文档,每个文档中都有相当数量的数据)。

正在像这样访问流:

  var cursor = db.domains.find({ html: { $exists: true } });

  cursor.on('data', function(rec) {
      i++;
      var url = rec.domain;
      var $ = cheerio.load(rec.html);
      checkList($, rec, url, i);
      // This "checkList" function parses HTML data with Cheerio to find different elements on the page. Lots of if/else statements
  });

  cursor.on('end', function(){
    console.log("Streamed all objects!");
  })

每条记录都用 Cheerio 进行解析(该记录包含 HTML 之前抓取的页面数据),然后我处理 Cheerio 数据以查找各种选择器,然后保存回 MongoDB.

对于前 ~2,000 个对象,数据解析速度非常快(约 30 秒)。之后它变得更慢,每秒解析大约 50 条记录。

查看我的 Macbook Air 的 activity 显示器,我发现它没有使用大量内存(226.5mb / 8gb ram),但它使用了大量 CPU(io.js 占了我的 99% cpu).

这可能是内存泄漏吗? checkLists 函数不是特别密集(或者至少,据我所知 - 有相当多的嵌套 if/else statements 但其他的不多)。

我是否打算在变量使用后清除它们,比如设置 $ = '' 或类似的? Node 的任何其他原因都会使用这么多 CPU?

您基本上需要 "pause" 流,否则 "throttle" 它会在立即收到的数据项上执行。因此 "event" 中的代码不会在触发下一个事件之前等待完成,除非您停止事件发射。

  var cursor = db.domains.find({ html: { $exists: true } });

  cursor.on('data', function(rec) {
      cursor.pause();    // stop processessing new events
      i++;
      var url = rec.domain;
      var $ = cheerio.load(rec.html);
      checkList($, rec, url, i);
      // if checkList() is synchronous then here
      cursor.resume();  // start events again
  });

  cursor.on('end', function(){
    console.log("Streamed all objects!");
  })

如果checkList()包含异步方法,则传入游标

      checkList($, rec, url, i,cursor);

并处理里面的"resume":

  function checkList(data, rec, url, i, cursor) {

      somethingAsync(args,function(err,result) {
          // We're done
          cursor.resume(); // start events again
      })
  }

"pause" 停止从流发出的事件,直到 "resume" 被调用。这意味着您的操作不会 "stack up" 在内存中并等待每个操作完成。

您可能需要对某些并行处理进行更高级的流控制,但这基本上就是您使用流进行处理的方式。 并在里面恢复