短い質問ですが、私には理解するのが難しいです。
ePoll が Poll よりも優れているのはなぜですか?
Damon の理由は、ソケットで決してブロックしない異常なケースでは正しいですが、典型的な現実世界のプログラムでは、理由はまったく異なります。典型的なプログラムは次のようになります。
1)今できることを全力でやる。
2) ネットワーク接続にサービスが必要かどうかを確認し、何もする必要がない場合はブロックします。
3) 検出されたすべてのネットワーク接続にサービスを提供します。
4) ステップ 1 に進みます。
通常、実行できる作業はすべて実行したので、ステップ 2 に戻った時点で、実行する作業はありません。そのため、少しお待ちいただく必要があります。ここで、関心のある 800 個のソケットがあるとします。カーネルは、これらの 800 個のソケットのそれぞれに対して待機キューを設定する必要があります。そして、データが 800 個のソケットの 1 つに到着する一瞬の後、カーネルはそれらの 800 個の待機キューからユーザーを削除する必要があります。タスクを待機キューに配置するには、そのタスクをその待機キューにリンクするための「サンク」を作成する必要があります。カーネルはどの 800 ソケットを待っているかを認識していないため、適切な最適化はできません。
ではepoll
、epoll ソケット自体に待機キューがあり、プロセスはその 1 つの待機キューにのみ置かれます。800 接続のそれぞれを epoll 待機キューにリンクするにはサンクが必要ですが、そのサンクは永続的です。epoll セットにソケットを追加して作成し、セットからソケットを削除するまでそこに残ります。
ソケットにアクティビティがある場合、カーネルはアクティビティを検出するタスクでそれを処理します。待機するとき、カーネルは検出されたイベントがあるかどうかを既に認識しており、カーネルはその 1 つの待機キューにユーザーを配置するだけで済みます。目を覚ますと、その 1 つのキューから削除するだけで済みます。
したがって、select
orpoll
を使用したキラーはコピーではなく、カーネルがブロック操作ごとに膨大な数の待機キューを操作する必要があるという事実です。
ポーリングシステムコールは、ファイル記述子のリストを毎回カーネルにコピーする必要があります。これは、で1回だけ発生しepoll_ctl
ますが、を呼び出すたびに発生するわけではありませんepoll_wait
。
また、監視される記述子の数に関してはepoll_wait
1です。つまり、1つの記述子で待機するか、5,000または50,000の記述子で待機するかは関係ありません。、よりも効率的ですが、それでも毎回リストをウォークオーバーする必要があります(つまり、記述子の数に関してです)。O(1)
poll
select
O(N)
そして最後に、epollは「通常」モードに加えて「エッジトリガー」モードで動作できます。つまり、カーネルは、準備ができたことを通知された後、読み取ったデータの量を追跡する必要がありません。このモードは把握するのがより困難ですが、いくらか効率的です。
epoll_wait
まだです。インターフェースを問わず、これとは異なる方法はほとんどありません。監視対象の記述子でN個のイベントが発生した場合、アプリケーションはN個の通知を受け取る必要があり、何が起こっているかに反応するためにN個の「処理」を実行する必要があります。
これもわずかに異なりますが、実際に。でイベントを取得するエッジトリガーモードでは基本的に違いはありません。エッジトリガーモードで、同じイベント(たとえば、O(N)
M
M <= N
POLLIN
)が数回発生すると、通知が少なくなる可能性があり、通知が1つだけになる可能性があります。ただし、これはビッグO表記自体についてはあまり変わりません。
ただし、監視される記述子epoll_wait
の数には関係ありません。意図された「通常の」方法(つまり、多くの記述子、少数のイベント)で使用されるという仮定の下で、これは本当に重要なことであり、ここでは実際にそうです。O(1)
例えとして、ハッシュテーブルを考えることができます。ハッシュテーブルはのコンテンツにアクセスしますが、ハッシュの計算は実際にはキーの長さに関するものであるO(1)
と主張することができます。これは技術的には絶対に正しいことであり、おそらくこれが問題になる場合がありますが、ほとんどの人にとって、これは問題ではありません。O(N)