Как детерминистически обработать ситуацию в NodeJS, где асинхронные функции используют память быстрее, чем сборщик мусора восстанавливает ее?

Я столкнулся с проблемой, когда у меня не хватает памяти, потому что сборка мусора не освобождает ресурсы достаточно эффективно, чтобы помешать многим асинхронным функциям использовать их все.

Я не храню ссылки на какие-либо объекты, созданные во время асинхронных функций, поэтому их все можно будет собирать после выхода из области видимости.

Я выполняю асинхронно через дерево каталогов, создавая простой текстовый файл для сопровождения каждого HTML-файла с использованием cheerio.

Я понимаю, что могу, но какая-то задержка или пакетная обработка, чтобы скрипт пытался конвертировать огромное количество файлов одновременно.

Но как я могу сделать это детерминистически? Иногда это работает, иногда я получаю исключение от cheerio, но каждый раз, работая над другим файлом, поэтому я думаю, что это исчерпание памяти и недетерминированное.

Я полагаю, что в JavaScript или NodeJS нет никакого способа контролировать сборку мусора. Что можно сделать?

Мой код:

var fs = require('fs')
  , path = require('path')
  , cheerio = require('cheerio')
  ;

var processFile = function(filePath) {
  var ext = path.extname(filePath)
    , res = false
    ;
  if (ext === '.html' || ext === '.htm') {
    res = true;

    fs.readFile(filePath, 'utf8', function(err, data) {
      var $;

      try {
        $ = cheerio.load(data);

        $('script').remove();

        // HTML to text
        var pt = $('body').text().replace(/(\s|\r?\n)+/gm, function (ws) {
          return /\r?\n.*\r?\n/.test(ws) ? '\n\n' : ' ';
        }).trim();

        var txtFilePath = filePath.substr(0, filePath.lastIndexOf('.')) + '.txt';
        fs.writeFile(txtFilePath, pt, function(err) {
          console.log('wrote "' + txtFilePath + '"');
        });
      } catch (exy) {
        console.log('## BANG!', filePath);
        throw exy;
      }
    });
  }
  return res;
}

var walkP = function(dir, done) {
  fs.readdir(dir, function(err, list) {
    if (err) return done(err);
    var pending = list.length;
    if (!pending) return done(null);
    list.forEach(function(file) {
      file = path.resolve(dir, file);
      fs.stat(file, function(err, stat) {
        if (stat && stat.isDirectory()) {
          walkP(file, function(err, res) {
            if (!--pending) done(null);
          });
        } else {
          processFile(file);
          if (!--pending) done(null);
        }
      });
    });
  });
};

walkP(process.cwd(), function(err, res) {
  console.log('Walked ' + res);
});

0 ответов

Другие вопросы по тегам