2016-07-26 4 views
1

У меня около 1000 CSV-файлов, которые нуждаются в разборе. Каждый из них содержит около 1000 строк, для 1 миллиона общих записей. Данные необходимо преобразовать, а затем сохранить в db, поэтому я должен сделать это через свое приложение.Метеор/Node.js синтаксический анализ большого количества файлов становится очень медленным

Моя проблема заключается в том, что анализатор постепенно замедляется, когда он перемещается по файлам, до такой степени, что это займет навсегда, чтобы завершить прогон.

Вот как он в настоящее время настроен.

var files = [ file1Path, file2Path.... file1000Path ]; 

function parseFile(index) { 
    var startTime = new Date().getTime(); 
    var filePath = files[index]; 
    var stream = fs.createReadStream(filePath); 

    //parse using fast-csv npm module 
    csv.fromStream(stream, { config }) 
    .on('data', function (row) { 
     transformAndSave(row); 
    }) 
    .on('end', function() { 
     console.log(new Date().getTime() - startTime + " elapsed "); 
     parseFile(index + 1) 
    }); 
} 
parseFile(0); 

Я пробовал это несколько разных способов, и каждый раз это одно и то же. Первый файл завершается через 2 секунды, восьмым файлом - 5 или 6 секунд, позже он поднимается до 24 секунд и т. Д. Другие вещи, которые я пробовал, включают в себя выполнение ... files.forEach(function (file) { //run the parser }), делая партии по 100 на время или даже 5 за раз, и это не имеет значения: он постепенно замедляется со скоростью 500 в секунду до 1 или 2 в секунду.

Есть ли у кого-нибудь идеи о том, как я могу предотвратить это? Отчасти причина может заключаться в том, что stream.on('end') завершает работу до завершения transformAndSave, потенциально создавая отставание. Но на данный момент у меня нет идей, и я был бы признателен за любую помощь, которую мог бы предложить любой.

Спасибо за много заранее!

Daniel


примечание для Метеор людей. Я называю эту функцию метеорным методом. Не уверен, что это имеет значение, но в случае, если это произойдет, теперь вы знаете.


Update Вот это выход журнала демонстрирует устойчивый рост использования памяти и времени обработки.

Log output

+0

В конце концов, я думаю, что это утечка памяти, связанная с метеоритом, поэтому я отмечаю @Mike P как правильный ответ. Спасибо, Майк! –

ответ

2

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

var Logger = require('arsenic-logger'); 
var fs = require('fs'); 
var async = require('async'); 
var csv = require('fast-csv'); 
var path = require('path'); 

Logger.echoMemoryUsage(); 

var testDir = path.resolve(__dirname, 'test'); 

fs.readdir(testDir, (err, files) => { 

    Logger.debug(files); 

    if (err) { 
     Logger.error(err); 
    } 

    async.mapLimit(files, 2, function(file, cb) { 

     var startTime = new Date().getTime(); 
     var stream = fs.createReadStream(testDir+'/'+file); 

     Logger.debug("Reading: " + file); 

     config = {}; 

     //parse using fast-csv npm module 
     csv.fromStream(stream, config) 
      .on('data', function(row) { 
       //Logger.debug(row); 
       //transformAndSave(row); 
      }) 
      .on('error', function(err) { 
       Logger.error(err); 
       cb(err); 
      }) 
      .on('end', function() { 
       Logger.debug(new Date().getTime() - startTime + " elapsed "); 
       setTimeout(cb, 1000); 
      }); 

    }, function(err, results) { 
     Logger.info("Finished!"); 
     process.exit(1); 
    }); 

}); 
+0

Спасибо за ваш быстрый ответ. Этот подход имеет смысл, но он все еще читает все файлы в поток все сразу. '.on ('end')' не вызывается для каждого файла. Я что-то упускаю? Еще раз спасибо. Daniel –

+0

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

+1

Итак, я тестировал, и он, кажется, закрывает поток каждый раз. Я обновил свой ответ с более полным кодом. Я использовал arsenic-logger (мой проект), поскольку Logger выплевывает использование памяти, чтобы вы могли видеть, как память освобождается с течением времени. –