CPUにバインドされているが、高性能I/O要件もあるアプリケーションについて考えてみます。
LinuxファイルI/OをWindowsと比較していますが、epollがLinuxプログラムにどのように役立つかはまったくわかりません。カーネルは、ファイル記述子が「読み取る準備ができている」ことを通知しますが、データを取得するには、blocking read()を呼び出す必要があります。メガバイトを読み取りたい場合は、それがブロックされることは明らかです。
Windowsでは、OVERLAPPEDが設定されたファイルハンドルを作成し、ノンブロッキングI / Oを使用して、I / Oが完了したときに通知を受け取り、その完了関数からのデータを使用できます。データを待つためにアプリケーションレベルの実時間を費やす必要はありません。つまり、スレッドの数をコアの数に正確に調整し、100%効率的なCPU使用率を得ることができます。
Linuxで非同期I/Oをエミュレートする必要がある場合は、これを行うためにいくつかのスレッドを割り当てる必要があります。これらのスレッドは、CPUの処理に少し時間を費やし、I/Oのブロックに多くの時間を費やします。さらに、これらのスレッドとの間のメッセージングにオーバーヘッドが発生します。したがって、CPUコアを過剰にサブスクライブするか、十分に活用しません。
mmap()+ madvise()(WILLNEED)を「貧乏人の非同期I / O」と見なしましたが、完了したときに通知を受け取ることができないため、まだそこまで到達していません。 「推測」し、「間違っている」と推測すると、メモリアクセスがブロックされ、ディスクからデータが送信されるのを待ちます。
Linuxはio_submitで非同期I/Oを開始しているようで、ユーザースペースのPOSIX aio実装もあるようですが、しばらくの間そのようになっており、これらのシステムを批判的に保証する人は誰もいません。 、高性能アプリケーション。
Windowsモデルはおおよそ次のように機能します。
- 非同期操作を発行します。
- 非同期操作を特定のI/O完了ポートに関連付けます。
- そのポートで操作が完了するのを待ちます
- I / Oが完了すると、ポートで待機しているスレッドはブロックを解除し、保留中のI/O操作への参照を返します。
ステップ1/2は通常、1つのこととして実行されます。ステップ3/4は通常、I / Oを発行するのと同じスレッドではなく、(必然的に)ワーカースレッドのプールを使用して実行されます。このモデルは、boost :: asioが提供するモデルと多少似ていますが、boost :: asioが実際には非同期のブロックベース(ディスク)I/Oを提供しない点が異なります。
Linuxでのepollとの違いは、ステップ4ではI / Oがまだ発生していないことです。ステップ1は、ステップ4の後に続きます。これは、必要なものが正確にわかっている場合は「逆方向」です。
多数の組み込み、デスクトップ、およびサーバーオペレーティングシステムをプログラムしたので、この非同期I / Oのモデルは、特定の種類のプログラムにとって非常に自然であると言えます。また、非常に高スループットで低オーバーヘッドです。これは、APIレベルでのLinux I/Oモデルの残りの本当の欠点の1つだと思います。