web-dev-qa-db-ja.com

.NETソケットとC ++ソケットの高性能

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

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

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

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

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

45
mdarsigny

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

唯一の参照は実装(つまり、Reflectorまたは他のAssemblyデコンパイラー)だと思います。これにより、all非同期IOはIO完了ポートを通過し、コールバックはIOスレッドで処理されます。プール(通常のスレッドプールとは別です)。

5つの完了ポートを使用する

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

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

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

「...ソケットの使用」部分をどの程度狭く定義するかに応じて、「はい」または「いいえ」。非同期操作の開始から完了が完了ポートにポストされるまでの操作に関しては、大きな違いはないと思います(すべての処理はWin32 APIまたはWindowsカーネルで行われます)。

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

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

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

8
Richard

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

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

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

6
jgauffin

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

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

1