46

私の質問は、同僚と C++ と C# の議論を解決することです。

大量の UDP ストリームを受信するサーバーを実装しました。このサーバーは、完了ポートを使用して非同期ソケットとオーバーラップ I/O を使用して C++ で開発されました。5 つのスレッドで 5 つの完了ポートを使用します。このサーバーは、ギガビット ネットワークで 500 Mbps のスループットをパケットの損失やエラーなしで簡単に処理できます (500 Mbps を超えるテストは行いませんでした)。

C# で同じ種類のサーバーを再実装しようとしましたが、同じ受信スループットに到達できませんでした。ReceiveAsyncメソッドとプールを使用した非同期受信を使用してSocketAsyncEventArgs、受信呼び出しごとに新しいオブジェクトを作成するオーバーヘッドを回避しています。それぞれSAEventArgsにバッファが設定されているため、受信ごとにメモリを割り当てる必要はありません。プールは非常に大きいため、100 を超える受信要求をキューに入れることができます。このサーバーは、240 Mbps を超える受信スループットを処理できません。その制限を超えると、UDP ストリームでいくつかのパケットが失われます。

私の質問は次のとおりです。C++ ソケットと C# ソケットを使用して同じパフォーマンスを期待する必要がありますか? 私の意見では、.NET でメモリが正しく管理されていれば、同じパフォーマンスになるはずです。

副次的な質問: .NET ソケットが内部で I/O 完了ポートをどのように使用するかを説明している良い記事/リファレンスを知っている人はいますか?

4

3 に答える 3

8

.NET ソケットが内部で I/O 完了ポートを使用する方法を説明する優れた記事/リファレンスを知っている人はいますか?

唯一の参照は実装 (つまり、Reflector またはその他のアセンブリ逆コンパイラ) であると思われます。これにより、すべての非同期 IO が IO 完了ポートを通過し、コールバックが IO スレッド プール (通常のスレッド プールとは別のもの) で処理されることがわかります。

5つの完了ポートを使用

単一の完了ポートを使用して、すべての IO をスレッドの単一のプールに処理し、プールごとに 1 つのスレッドが完了を処理することを期待します (ディスクを含む他の IO も非同期で行っていると仮定します)。

なんらかの優先順位付けが行われている場合、複数の完了ポートは理にかなっています。

私の質問は次のとおりです。C++ ソケットと C# ソケットを使用して同じパフォーマンスを期待する必要がありますか?

はいまたはいいえ、「ソケットを使用する」部分をどれだけ狭く定義するかによって異なります。非同期操作の開始から完了が完了ポートに送信されるまでの操作に関しては、大きな違いはないと予想されます (すべての処理は Win32 API または Windows カーネルで行われます)。

ただし、.NET ランタイムが提供する安全性により、いくらかのオーバーヘッドが追加されます。例えば。バッファー長がチェックされ、デリゲートが検証されます。アプリケーションの制限が CPU である場合、これが違いを生む可能性が高く、極端な場合、わずかな違いが簡単に加算される可能性があります。

また、.NET バージョンは GC のために一時停止することがあります (.NET 4.5 は非同期収集を行うため、これは将来改善される予定です)。ガベージの蓄積を最小限に抑える手法があります (たとえば、オブジェクトを作成するのではなく再利用する、ボックス化を回避しながら構造を利用する)。

最終的に、C++ バージョンが機能し、パフォーマンスのニーズを満たしているのであれば、なぜ移植するのでしょうか?

于 2011-12-11T17:04:28.323 に答える
6

C ++からC#へのコードのストレートポートを実行して、同じパフォーマンスを期待することはできません。.NETは、メモリ管理(GC)と、コードの安全性(境界チェックなど)の確認に関して、C++よりもはるかに多くのことを行います。

すべてのIO操作(たとえば、65535 x 500 = 32767500バイト)に1つの大きなバッファーを割り当ててから、それぞれにSocketAsyncEventArgs(および送信操作に)チャンクを割り当てます。メモリはCPUよりも安価です。バッファーマネージャー/ファクトリを使用して、すべての接続とIO操作(Flyweightパターン)にチャンクを提供します。MicrosoftはAsyncの例でこれを行っています。

Begin / EndメソッドとAsyncメソッドはどちらも、バックグラウンドでIO完了ポートを使用します。後者は、パフォーマンスを向上させる操作ごとにオブジェクトを割り当てる必要はありません。

于 2011-12-11T18:25:56.257 に答える
1

私の推測では、.NET と C++ は実際には異なることを行っているため、同じパフォーマンスが得られていないということです。C++ コードは安全ではないか、境界をチェックしている可能性があります。また、何も処理せずにパケットを受信する能力を測定しているだけですか? それとも、スループットにパケット処理時間が含まれていますか? その場合、パケットを処理するために作成したコードは効率的ではない可能性があります。

プロファイラーを使用して、最も時間が費やされている場所を確認し、それを最適化することをお勧めします。実際のソケット コードは非常にパフォーマンスが高いはずです。

于 2011-12-11T17:29:24.953 に答える