2012-11-21 9 views
10

Node.js/Express RESTful APIから非常に大きなオブジェクトをJSON文字列に変換する必要がある場合があります。Node.js/ExpressでのJSON.stringify出力のストリーミング/パイプ

res.end(JSON.stringify(obj)); 

しかし、これはうまくスケールされていません。具体的には、1-2台のクライアントを接続している私のテストマシンではうまくいきますが、多くのクライアントが同時に大規模なJSONオブジェクトを要求しているときに、この操作によってCPU使用率がになっている可能性があります。

私は非同期JSONライブラリを探し回っていますが、the only one I foundに問題があるようです(具体的には、[RangeError]が表示されます)。それだけでなく、1つの大きなチャンクに文字列を返します(たとえば、コールバックは文字列全体で1回呼び出されます。つまり、メモリのフットプリントは減少しません)。

JSON.stringify関数の完全非同期パイプ/ストリーミングバージョンです。ストリームに直接パックされたデータを書き込むようにしています。同期的にCPUを消費します。

+0

ストリームを作成し、オブジェクトをストリングとしてストリームに書き込み、最後にストリームをパイプします。 res。 – wayne

答えて

9

理想的には、すべてのデータを1つのラージオブジェクトにバッファリングするのではなく、データをストリーミングする必要があります。これを変更できない場合は、stringifyをより小さな単位に分割し、メインイベントループがsetImmediateを使用して他のイベントを処理できるようにする必要があります。例コード(メインオブジェクトには多くのトップレベルプロパティがあり、それらを使って作業を分割すると仮定します)

function sendObject(obj, stream) { 
    var keys = Object.keys(obj); 
    function sendSubObj() { 
     setImmediate(function(){ 
      var key = keys.shift(); 
      stream.write('"' + key + '":' + JSON.stringify(obj[key])); 
      if (keys.length > 0) { 
      stream.write(','); 
      sendSubObj(); 
      } else { 
      stream.write('}'); 
      } 
     }); 
    }) 
    stream.write('{'); 
    sendSubObj(); 
} 
+0

いい実装、ありがとう! –

+0

これは、objのトップレベルからのキー名とオブジェクトの詳細を省略していますか? – Paul

+0

はい、あなたは正しいです。コードを更新します –

5

Dominic TarrさんのJSONStreamが好きなようです。明らかに、これを明示的にマージする必要があるアセンブリがあります。あなたは(文字列化)オブジェクトをシリアル化しようとするCPUを限界いっぱいまでされている場合

しかし、その後、チャンクに働く分割は本当に問題が解決しない場合があります。ストリーミングはメモリ占有量を減らすかもしれませんが、必要な "仕事"の総量を減らすことはありません。

+0

これは、作業の総量を減らすことはできませんが、時間の経過とともに(process.nextTickで分けて)それを分散させることは、CPUが固定されないことを意味します。 –

+2

注:process.nextTickは、イベントループに戻る前に実行されるようになりました。 'setImmediate'を使います。 – CoolAJ86

関連する問題