どちらのアプローチがより高速で、なぜですか?
Win32 サーバーを作成しているときに、完了ポートとオーバーラップ I/O について多くのことを読みましたが、どの API のセットがサーバーで最良の結果をもたらすかを示唆するものは何も読んでいませんでした。
完了ルーチンを使用する必要がありますか、それとも WaitForMultipleObjects API を使用する必要がありますか? その理由は?
どちらのアプローチがより高速で、なぜですか?
Win32 サーバーを作成しているときに、完了ポートとオーバーラップ I/O について多くのことを読みましたが、どの API のセットがサーバーで最良の結果をもたらすかを示唆するものは何も読んでいませんでした。
完了ルーチンを使用する必要がありますか、それとも WaitForMultipleObjects API を使用する必要がありますか? その理由は?
重複した I/O を実行する 2 つの方法を提案し、3 番目の方法は無視します (または、質問を誤解しています)。
重複した操作(たとえば、 WSARecv())を発行する場合、イベントを含む OVERLAPPED 構造体を指定し、そのイベントが通知されて重複した I/O が完了したことを示すのを待つことができます。これは、あなたの WaitForMultipleObjects() アプローチであり、前述のように、WaitForMultipleObjects() に渡すことができるハンドルの数に制限があるため、これはうまくスケーリングしません。
または、完了が発生したときに呼び出される完了ルーチンを渡すこともできます。これは「アラート可能な I/O」と呼ばれ、完了ルーチンを呼び出すには、WSARecv() 呼び出しを発行したスレッドが「アラート可能な」状態にある必要があります。スレッドは、いくつかの方法 (SleepEx() または待機関数のさまざまな EX バージョンの呼び出しなど) でアラート可能な状態にすることができます。私が目の前で開いているリヒターの本には、「私はアラート可能な I/O をかなり扱ってきましたが、アラート可能な I/O は恐ろしいものであり、避けるべきであることを最初にお伝えします」と書かれています。私見は十分に言った。
3 つ目の方法として、呼び出しを発行する前に、オーバーラップ I/O を実行するハンドルを完了ポートに関連付ける必要があります。次に、GetQueuedCompletionStatus() を呼び出してループすることにより、この完了ポートを処理するスレッドのプールを作成します。イベントを含まない OVERLAPPED 構造を使用して WSARecv() を発行すると、I/O が完了すると、I/O プール スレッドの 1 つで GetQueuedCompletionStatus() から完了がポップアウトされ、そこで処理できます。
前述のように、Vista/Server 2008 では IOCP の動作が少しクリーンアップされ、オーバーラップしたリクエストを発行したスレッドがリクエストが完了するまで実行し続けなければならないという問題が解消されました。への参照へのリンクは、ここにあります。ただし、この問題は簡単に回避できます。補完に使用するのと同じIOCPを使用して、WSARecvをI / Oプールスレッドの1つにマーシャリングするだけです...
とにかく、IOCP を使用する IMHO は、重複した I/O を実行するための最良の方法です。はい、呼び出しの重複/非同期の性質に頭を悩ませるには、最初は少し時間がかかる場合がありますが、システムは非常にうまくスケーリングし、重複した操作を処理する単純な「ファイアアンドフォーゲット」方法を提供するため、それだけの価値があります.
作業を開始するためにサンプル コードが必要な場合は、IO 完了ポート システムの作成に関するいくつかの記事と、ハイ パフォーマンス サーバー用の実際のフレームワークを提供するフリー コードのヒープがあります。ここを参照してください。
余談として; 私見ですが、Jeffrey Richter と Christophe Nasarre による " Windows Via C/C++ (PRO-Developer) " を読む必要があります。重複した I/O やその他の高度な Windows プラットフォームのテクニックや API について知っておく必要があるすべてのことを扱っているからです。
WaitForMultipleObjects
64 ハンドルに制限されています。並行性の高いアプリケーションでは、これが制限になる可能性があります。
完了ポートは、すべてのイベントを処理できるスレッドのプールを持つモデルにより適しています。独自の (非 IO ベースの) イベントをポートにキューに入れることができますが、待機の場合は独自のコーディングが必要になります。機構。
ただし、完了ポートとイベント ベースのプログラミング モデルは、実際に対処するのがより難しい概念です。
パフォーマンスに大きな違いはないと思いますが、最終的には、使用状況を反映するために独自の測定を行うことしかできません. Vista/Server2008 では完了ポートが変更され、IO 操作を完了するために元のスレッドが必要なくなったことに注意してください。これにより、より大きな違いが生じる可能性があります ( Mark Russinovich によるこの記事を参照してください)。
『 Microsoft Windows用ネットワークプログラミング、第2版』の表6-3は、完了ポートを介したオーバーラップI/Oのスケーラビリティと他の手法を比較しています。完了ポートは、スループットに関しては、他のすべてのI / Oモデルを水から吹き飛ばしますが、使用するスレッドははるかに少なくなります。
WaitForMultipleObjects() と I/O 完了ポートの違いは、IOCP は数千のオブジェクトにスケーリングされるのに対し、WFMO() は 64 個を超えるオブジェクトには使用されず、使用されるべきではありません (使用できたとしても)。
64 個未満のオブジェクトのドメインでは、それらは本質的に同一であるため、実際にパフォーマンスを比較することはできません。
ただし、WFMO() はそのオブジェクトに対してラウンド ロビンを実行するため、インデックス番号が小さいビジー状態のオブジェクトは、インデックス番号が大きいオブジェクトを枯渇させる可能性があります。(たとえば、オブジェクト 0 が絶えずオフになっている場合、オブジェクト 1、2、3 などを枯渇させます)。これは明らかに望ましくありません。
C10K の問題を解決するために (ソケット用の) IOCP ライブラリを作成し、パブリック ドメインに置きました。512MB の W2K マシンで、データを同時に転送する 4,000 ソケットを取得できました。(ソケットがアイドル状態の場合は、より多くのソケットを取得できます。ビジー状態のソケットは、より多くの非ページ プールを消費します。これが、保持できるソケット数の最終的な制限です)。
http://www.45mercystreet.com/computing/libiocp/index.html
API は、必要なものを正確に提供する必要があります。
わからない。しかし、私は WaitForMultipleObjects や WaitFoSingleObjects を使用しています。とても便利です。
どちらのルーチンも機能し、一方が他方よりも大幅に速いとは思いません。
これら 2 つのアプローチは、異なるプログラミング モデルを満たすために存在します。WaitForMultipleObjects は非同期完了パターン (UNIX の select() 関数など) を容易にするためにありますが、完了ポートはイベント駆動型モデルに向いています。
個人的には、WaitForMultipleObjects() アプローチの結果、コードがよりクリーンになり、スレッド セーフが向上すると思います。