2016-07-26 73 views
1

我有大約1000個需要解析的CSV文件。每個包含大約1000行,總計100萬條記錄。數據需要轉換,然後保存到數據庫,這就是爲什麼我必須通過我的應用程序來做到這一點。解析大量文件的流星/節點.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秒內完成,在第8個文件中我們在5或6秒鐘,稍後再爬到24秒鐘等。我試過的其他東西包括做... files.forEach(function (file) { //run the parser }),時間甚至是5次,並沒有什麼區別:它從每秒500次的速度逐漸減慢到每秒1次或2次。

有沒有人有想法,我可以如何防止這種放緩?部分原因可能是在transformAndSave完成之前完成,可能會產生積壓。但是在這一點上,我沒有想法,並希望任何人都可以提供幫助。

非常感謝您提前!

丹尼爾


記爲流星的人。我將這個函數作爲Meteor方法來調用。不知道這是否有所作爲,但如果它確實如此,現在你知道了。


更新 這裏的是日誌輸出展示在內存使用和處理時間的穩步上升。

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')'沒有被每個文件調用。我錯過了什麼嗎?再次感謝。丹尼爾 –

+0

它應該讀取每個文件到一個單獨的流,並關閉它。它最好也使用async.mapLimit,所以它可以批量使用它們。我會試驗並看到...... –

+1

所以我測試了一下,它似乎每次都會關閉流。我用更完整的代碼更新了我的答案。當記錄器吐出內存使用情況時,我使用了砷記錄器(我的項目),以便隨着時間的推移可以看到內存正在釋放。 –