2016-11-21 1 views
2

マイライブラリメモリ不足.MAP: Javascriptが -

const Promise = require('bluebird'); 
const fs = Promise.promisifyAll(require('graceful-fs')); 
const path = require('path'); 
const xml2js = Promise.promisifyAll(require('xml2js')); 

は、私が解析したいXMLファイルの数が多いです。

function getFileNames(rootPath) { 
    // Read content of path 
    return fs.readdirAsync(rootPath) 
    // Return all directories 
    .then(function(content) { 
     return content.filter(function(file) { 
     return fs.statSync(path.join(rootPath, file)).isDirectory(); 
     }); 
    }) 
    // For every directory 
    .map(function(directory) { 
     // Save current path 
     let currentPath = path.join(rootPath, directory); 
     // Read files in the directory 
     return fs.readdirAsync(currentPath) 
     // Filter out the XMLs 
     .filter(function(file) { 
      return path.extname(file) === '.XML'; 
     }) 
     // Return path to file 
     .map(function(file) { 
      return path.join(rootPath, directory, file); 
     }); 
    }) 
    // Flatten array of results 
    .reduce(function(a, b) { 
     return a.concat(b); 
    }); 
} 

を、今私はすべて1つのファイルを谷とそれを解析行きたい:私はこの機能を使用して、すべてのファイルへのパスの配列を作成することができています。

私はそうする2機能があります。今、私は.MAP(GetFileNames関数は、ファイルパスと20Kを超える文字列の配列を出力)機能でこれを呼び出すとき

function openFile(filePath) { 
return fs.readFileAsync('./' + filePath) 
    .then(function(fileData) { 
    return fileData; 
    }); 
} 

function parseFile(data) { 
    return xml2js.parseStringAsync(data) 
     .then(function(xmlObject) { 
     return xmlObject; 
     }); 
} 

を:

getFileNames('./XML') 
    .map(function(file) { 
    openFile(file) 
     .then(function(data) { 
     parseFile(data) 
      .then(function(object) { 
       console.log(object); 
      }); 
     }); 
    }); 

私はメモリエラーのうち、JavaScriptのヒープを得る:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory

しかし、ときに私が実行します実際のファイルへのパスを渡すことで、関数を1回だけ実行することができます。

openFile('./XML/2016-10-1/EUROTIPOLD2016-10-1T00-00-22.5756240530.XML') 
    .then(function(data) { 
    parseFile(data) 
     .then(function(object) { 
      console.log(object); 
     }); 
    }); 

目的の出力が得られます。

私は間違っていますか?

+0

あなたは何とか代わりに、それが動作するハードコードされた文字列のvaraibleを使用するときに、あなたは言っています? – epascarello

+0

申し訳ありませんが、質問を編集しました。私は、関数を実行するときに.map関数を使わずに関数を実行すると、(ファイルへのパスを含む文字列を渡すことによって)動作すると言います。私が.map関数の中で実行すると、メモリが足りなくなります。 –

+1

開こうとしたファイルの数はいくつですか?非同期関数を忘れないでください。Node.jsは、すべてのファイルを1つずつ開くのではなく、同時に開くようにします。 – Fefux

答えて

1

は非同期に行われます。

1)あなたはopenFileを呼んでいる.map行うことによって)ファイル

2のリストを取得している、parseFile非同期関数であり、それは読んで解析するのに時間がかかります。


だからasynchronousityのそれはメモリを掃引するガベージコレクタを呼び出す前のものを完了を待たずに次のファイルに進み、ここではメモリ不足の問題ですので。

は、一度に様々なサイズで20Kファイルを読み込むについて考えてみよう。

使用async同期(eachSeries)またはコントロール(eachLimit)反復する:


は、だからここソリューションです。

const async = require('async'); // install: npm i --save async 

let files = getFileNames('./XML'); 

// eachLimit(files, 3, 
async.eachSeries(files, 
    (file, next) => { 
    openFile(file) 
    .then(
     parseFile, 
     (err) => { 
     console.error('Cannot open file:', file, err); 
     next(); 
     }) 
    .then(
     object => { // successfully parsed file, so log it out and proceed to next file 
     console.log(object); 
     next(); 
     }, 
     (err) => { 
     console.error('Cannot parse data from file:', file, err); 
     next(); 
     }); 
}); 

p.s.私の答えでコメントしてコードの問題を修正してください。

+1

使用しませんでした私の問題を解決したasync.eachSeriesの使用を開始しました。ありがとう –

+0

@MihaŠušteršič実際にはそれは〜例でした(あなたはあなたのコードを自由に定義することができます – num8er

0

これはあなたのワークロードのためのより多くのリソース要件の単純なケースです。私は、ソースコードを変更するのではなく、ヒープサイズを増やすことで需要を満たすことを検討します。

私は要件を満たすためにそれに応じて設定すること--max_old_space_sizeをお勧めします - それはしかし、反復プロセスであってもよいです。

これが役に立ちます。 nKファイルを反復

+0

これは他に問題がない場合、最後の手段のようなものです。最初に問題をデバッグして、できるだけ修正または最適化する方が良いです。サーバーの負荷レベルに応じてノードプロセスにさらに多くのリソースを提供することができます。 –