0

画像やファイルをダウンロードしたいと想像してみてください。これは、インターネットが教えてくれる最初の方法です。

request(url, function(err, res, body) {
    fs.writeFile(filename, body);
});

しかし、これではすべてのデータが に蓄積されbody、メモリがいっぱいになりませんか? はpipe完全に効率的でしょうか?

request(url).pipe(fs.createWriteStream(filename));

それとも、これは同様の問題で内部的に処理され、とにかくストリームをバッファリングして、これを無関係にしますか?

さらに、コールバックを使用したいが (まだ使用できるため) を使用したくない場合、このメモリ バッファーはまだいっぱいになりますか?bodypipe

最初の(コールバック)メソッドを使用すると、ダウンロードを並行して起動する代わりに(*)ダウンロードをチェーンできるため、質問していますが、どちらも使用しないバッファを埋めたくありません。したがって、キューを使用してこれを防ぐためだけにasyncのような派手なものに頼りたくない場合は、コールバックが必要です。

(*)requestファイルが完成する前にファイルが多すぎると、 の非同期の性質requestにより、イベントの過剰摂取とメモリの損失でノードが窒息死するため、これは悪いことです。まず、次のものを取得します。

"possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit."

そして、それを拡張すると、500 のパイプ リクエストでメモリがいっぱいになり、ノードがクラッシュします。そのため、パイプの代わりにコールバックが必要なため、次のファイルをいつ開始するかがわかります。

4

2 に答える 2

3

でも、これだと本体にデータが溜まってメモリがいっぱいになってしまうのではないですか?

はい、最初のスニペットなどの多くの操作は、データをメモリにバッファリングして処理します。はい、これはメモリを使用しますが、少なくとも便利であり、そのデータをどのように処理するかによっては必要になる場合があります。HTTP 応答をロードして本文を JSON として解析する場合、ほとんどの場合、バッファリングを介して行われますが、ストリーミング パーサーを使用すると可能ですが、はるかに複雑で、通常は不要です。ほとんどの JSON データは十分に大きくないため、ストリーミングが大きな効果を発揮します。

それとも、これは同様の問題で内部的に処理され、これは無関係になりますか?

いいえ、データ全体を文字列として提供する API は、ストリーミングではなくバッファリングを使用します。

ただし、マルチメディア データは現実的にはメモリにバッファリングできないため、ストリーミングの方が適しています。また、そのデータは不透明になる傾向があり (解析したり処理したりしません)、ストリーミングにも適しています。

状況が許せばストリーミングは便利ですが、だからといってバッファリングに問題があるとは限りません。真実は、ほとんどの場合、ほとんどの場合、バッファリングがどのように機能するかということです。全体像としては、ストリーミングは一度に 1 つのチャンクをバッファリングし、利用可能なリソースの範囲内にあるサイズ制限でそれらを制限するだけです。データを処理する場合、データの一部はある時点でメモリを通過する必要があります。

あまりにも多くのファイルを 1 つずつ要求すると、要求の非同期性により、イベントの過剰摂取とメモリ損失でノードが窒息死するためです。

ここで何を言っているのか、何を尋ねているのか正確にはわかりませんが、効果的なプログラムを作成するには、リソースと効率について考える必要があります。

ハイパークエスト README のストリーミング/プーリングに関するサブスタックの暴言も参照してください。

于 2013-11-08T01:46:24.343 に答える
1

メモリに関する質問を無関係にする解決策を見つけました (ただし、まだ興味があります)。

コールバックを使用したいが (まだ使用できるため) を使用したくない場合、この メモリバッファーはまだいっぱいになりますか?bodypipe

リクエストがいつ終了したかを知るためにcallbackfromは必要ありません。request()「終了」pipe()すると、 は自動的に閉じます。streamクローズはイベントを発行し、次のことをリッスンできます。

request(url).pipe(fs.createWriteStream(filename)).on('close', function(){           
    next();
});

これで、すべてのリクエストをキューに入れ、ファイルを 1 つずつダウンロードできます。

もちろん、 などのライブラリを使用して常に 8 つの並列リクエストを使用してインターネットをバキュームすることasync.queueはできますが、単純なスクリプトでいくつかのファイルを取得するだけの場合asyncは、おそらくやり過ぎです。

それに、とにかくマルチユーザー システムで 1 つのトリックのためにシステム リソースを使い果たしたくはありません。

于 2013-11-08T03:19:46.797 に答える