4

RegisterWaitForSingleObjectI/O 完了ポートを使用することと、I/O が完了するまでスレッド プールのスレッドを待機させるために使用することの違いは何ですか?

そのうちの 1 つは高速ですか? もしそうなら、その理由は?

4

1 に答える 1

8

IOCP は、一般に最も高速に実行される IO ターンアラウンド メカニズムであり、その理由の 1 つは、ブロック検出です。

これの簡単な例は、ディスクからファイルを提供する役割を担うサーバーです。IOCP は一般に、次の 3 つの主要なもので構成されます。

  1. IOCP 要求を処理するための N スレッドのプール。
  2. M スレッドの制限 (M は常に < N) は、ブロックされていない並行スレッドをいくつ許可するかを IOCP に指示します。
  3. すべてのスレッドが実行される完了ステータス ループ。

この点での N と M の違いは非常に重要です。一般的な考え方は、M をマシンのコア数に設定し、N をそれより大きくすることです。どの程度大きくなるかは、ワーカー スレッドがブロック状態で費やす時間によって異なります。ディスク ファイルを読み取っている場合、スレッドはディスク IO チャネルの速度に拘束されます。その呼び出しを行うとReadFile()、ブロッキング呼び出しが導入されました。M == N の場合、ディスク ファイルを読み取るすべてのスレッドにヒットするとすぐに、すべてのスレッドがディスク IO チャネル上で完全に停止します。

しかし、このスレッドが (a) IOCP スレッド プールに参加しており、(b) 時間のかかる API 呼び出しを発行したために停止しただけであることを、手の込んだスケジューラが「知る」方法があったとしたらどうでしょうか? それが起こったとき、その手の込んだスケジューラーが一時的にそのスレッドを特別な「running-but-stalled」グループに「移動」し、その後、スレッドが停止している間に自発的に動作する余分なスレッドを「解放」できたらどうでしょうか?

それがまさにIOCP がもたらすものです。N がMより大きい場合、IOCP は、ストールを発行したばかりのスレッドを特別な実行中だがストールした状態にし、N のプールから追加のスレッドを一時的に「借用」します。 N プールが使い果たされるか、停止していたスレッドがブロッキング要求から戻り始めます。

したがって、その光の下では、たとえば 8 コアのマシンで同時に実行される 8 つのスレッドを持つように構成された IOCP は、実際には実際のプールに数百のスレッドを持つことができます。ブロックされていない状態で同時に実行できるのは 8 つだけです。

最後に、あなたの原因にとってはそれほど重要ではありませんが、それでも重要です。IOCP スレッドは、現在の作業を終了して次のGetQueueCompletionStatus()呼び出しを発行するときにキューに保留中の作業がある場合、ブロックもコンテキスト スイッチも行いません。待機中の作業がある場合は、それを取得し、強制的なプリエンプションなしで実行を継続します。もちろん、OS スケジューラはいずれにせよプリエンプションを実行できますが、それは一般的なスケジューラの一部としてのみです。への特定の呼び出しのためではありませんGetQueueCompletionStatus()。これに対する唯一の例外は、既に M 個以上のスレッドが実行されていて、ブロックされていない場合です。その場合、GetQueueCompletionStatus()十分な数のスレッドが再びブロックされたときに、slack-work のために再度必要になるまで、呼び出し元のスレッドをブロックします。

あなたが与えた説明は、あなたが非常にディスクIOに縛られていることを示しています。絶対的なパフォーマンスが重要な io サーバー アーキテクチャの場合、IOCP の利点、特に、マスター プールから余分なスレッドを一時的に解放して物事を維持できることをスケジューラが認識できるようにする OS レベルのブロック検出を打ち負かすことはほぼ不可能です。他のスレッドが停止している間にポンピングします。

Windows スレッド プールを使用して IOCP の特定の機能を複製することはできません。すべてのスレッドが IO がほとんどまたはまったくない数値計算機である場合、スレッドプールの方が適していると思いますが、ディスク IO の特異性から、代わりに IOCP を使用する必要があることがわかります。

于 2013-04-26T19:29:13.273 に答える