5

私の小さな小さなファイル転送 Web サイト ( .NET 4.5.1 を実行しているこのサイト) では、Microsoft Knowledge Base の記事812406 に従って、以前にアップロードしたファイルをサーバーからブラウザーに送信しています。

パフォーマンスの最適化を行っているときに驚いたのは、

var buffer = new byte[10000];

かなりの時間がかかります (Red Gate のANTS Performance Profilerを使用しています)。バッファーは、完全なダウンロード/クライアントごとに 1 回だけ割り当てられます。

私の質問:

  • この方法でこのサイズのバッファを割り当てるのは良い習慣ですか?
  • ≈10k バッファを割り当てるための代替手段はありますか?

更新 1:

あなたのコメントのおかげで、ループ内でもメモリが割り当てられていることがわかりました。

それでも、ANTS Profilerは、ループの外側の割り当てにそれだけの時間がかかるようにマークするだけで、正直なところ (まだ) 理解できません。ループ内の (無意味な) 割り当てを削除しました。

更新 2:

提案を実装しBufferManager、バッファ サイズを 10k から 4096 に減らした (念のため...) ことで、私の Web サイトは何日も前から非常にスムーズに動作しています。

4

4 に答える 4

4

はい。実際、WCF はこの問題を防ぐために「バッファ マネージャ」を使用します

私は自分自身でネットワーク サービスを開発してきましたが、プロファイリング中に、Byte[]バッファーの割り当てがボトルネックになっていることがわかりました。割り当て中だけでなく、プロセッサが GC で浪費する時間も非常に長くなりました。これらのバッファーを再利用して割り当てを回避するための改善により、パフォーマンスが大幅に向上します。

このクラスを使用しBufferManagerて、独自のバッファー管理戦略を作成することを回避できます。

于 2014-04-05T19:29:48.967 に答える
4

オブジェクトの作成は通常、.NET では非常に高速ですが、この配列オブジェクトはサイズが大きいため、すべてのバイトをクリアするには長い時間がかかります。C# では常にすべてのバイト0が設定されるため、オブジェクトの作成時にすべてのフィールドがデフォルト値に設定されます。(もちろん、コンストラクターとフィールド初期化子は、クラスと構造体で異なる値を割り当てることができます。)

Microsoftの例では、バッファはループの前に割り当てられ、そのサイズは決して変更されません。さらに、出力ストリームへの書き込みでは、必要なバイトのみが書き込まれます。

// Gets the exact number of bytes read
length = iStream.Read(buffer, 0, 10000);

// Writes only 'length' bytes to the output
Response.OutputStream.Write(buffer, 0, length);

したがって、ループの反復ごとに新しいバッファを割り当ててバッファを「クリア」する必要はありません。ダーティな余分なバイトは問題ありません。

buffer= new Byte[10000];解決策: while ループ内に行をドロップしてください。

于 2014-04-05T19:43:00.567 に答える
1

そのようなコンストラクターを呼び出すと、特にそのような大きなバッファーを使用すると、間違いなく多くの CPU 時間がかかります。もちろん、あなたの質問に対する回答は意見に基づくものですが、私の回答は次のとおりです。

  1. そのサイズのバッファを割り当てることに問題はありません。10K は、最新のシステムではそれほど多くのメモリではありません。もちろん、どのような種類のループでもこれを行うと、CPU 時間が急速に消費されます。

  2. 可能であれば、使用するたびにバッファを再構築しないようにしてください。以前に定義されたバッファを使用すると、必要になるたびにメモリを再割り当てする必要がなくなります。もちろん、これがスレッド化されている場合 (複数の接続)、各接続/スレッドには独自のバッファーが必要ですが、リンクされた例のように、ストリーミングされたデータのすべての「チャンク」に対して新しいバッファーではなく、接続ごとに少なくとも 1 つの割り当てが必要です。

于 2014-04-05T19:27:21.377 に答える