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

时间:2015-07-16 02:33:37

标签: javascript node.js mongodb cpu-usage

我正在从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的活动监视器,我发现它没有使用疯狂的内存量(226.5mb / 8gb ram),但是它使用了大量的CPU(io.js占据了我的cpu的99%)

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

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

1 个答案:

答案 0 :(得分:4)

你基本上需要"pause"流或其他"油门"它直接从收到的非常数据项上执行。所以"事件中的代码"除非你停止发射事件,否则在下一个事件被触发之前不会在完成之前等待。

  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);

处理"简历"内:

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

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

"暂停"停止从流发出的事件,直到"恢复"叫做。这意味着您的操作不会叠加"在记忆中等待每一个完成。

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