回答:
ソケットの数が非常に少ない場合(もちろん、ハードウェアによって異なりますが、10以下のオーダーについて話している場合)、selectは、メモリ使用量と実行速度の点で優れています。もちろん、このような少数のソケットの場合、両方のメカニズムは非常に高速であるため、ほとんどの場合、この違いを気にする必要はありません。
ただし、説明が1つあります。selectとepollの両方が線形にスケーリングします。ただし、大きな違いは、ユーザー空間に面したAPIには、さまざまなことに基づいた複雑さがあることです。select
呼び出しのコストは、渡す番号が最も大きいファイル記述子の値にほぼ比例します。単一のfd、100を選択すると、単一のfd、50を選択する場合の約2倍のコストがかかります。最高よりも下にさらにfdを追加することは完全に無料ではないため、実際にはこれよりも少し複雑ですが、これはほとんどの実装では、最初の近似として適しています。
epollのコストは、実際にイベントが発生しているファイル記述子の数に近いです。200個のファイル記述子を監視しているが、そのうちの100個のみがイベントを持っている場合、100個のアクティブなファイル記述子に対してのみ(非常に大まかに)支払います。これが、epollがselectよりも大きな利点の1つを提供する傾向があるところです。ほとんどアイドル状態のクライアントが1,000ある場合、selectを使用しても、1000のクライアントすべてに対して料金を支払うことになります。ただし、epollを使用すると、ごく少数しか得られないように見えます。支払いを行うのは、常にアクティブなものだけです。
これはすべて、epollがほとんどのワークロードのCPU使用率を低下させることを意味します。メモリ使用量に関する限り、それはちょっとしたことです。 select
非常にコンパクトな方法(ファイル記述子ごとに1ビット)で必要なすべての情報を表すことができます。また、FD_SETSIZE(通常は1024)の制限で、使用できるファイル記述子の数が異なりますselect
数に対するにより、使用できる3つのfdセットのそれぞれに128バイトを超えることはありません。select
(読み取り、書き込み、例外)。これらの最大384バイトと比較すると、epollは一種の豚です。各ファイル記述子は、マルチバイト構造で表されます。ただし、絶対的には、メモリをあまり使用しません。数十キロバイトで膨大な数のファイル記述子を表すことができます(1000のファイル記述子あたり約20kと思います)。また、である、これらのバイトの384をすべて使用する必要があるという事実を投入することもできselect
1つのファイル記述子のみを監視したいが、その値が1024である場合、epollを使用すると、20バイトしか使用しません。それでも、これらの数値はすべて非常に小さいため、それほど大きな違いはありません。
また、epollには、FD_SETSIZEファイル記述子に限定されないという、おそらくすでにご存知のような他の利点もあります。これを使用して、必要な数のファイル記述子を監視できます。また、ファイル記述子が1つしかなく、その値がFD_SETSIZEより大きい場合、epollはそれでも機能しますが、select
機能しません。
ランダムに、私も最近、1つのわずかな欠点を発見したepoll
と比較しselect
たりpoll
。一方でこれらの3つのAPIのどれも、通常のファイル(ファイルシステム上、すなわち、ファイル)をサポートしていない、select
とpoll
常に読みやすく、常に書き込み可能のような記述子を報告するように、支持の欠如を提示します。これにより、意味のある種類の非ブロッキングファイルシステムI / Oには不向きになります。ファイルシステムのファイル記述子を使用する、select
またはpoll
偶然に遭遇するプログラムは、少なくとも動作し続けます(または、失敗した場合、それは原因ではありません。のselect
かpoll
)、それにもかかわらず、おそらくない最高の性能を持ちます。
一方、そのようなファイル記述子を監視するように要求された場合、epoll
はエラー(EPERM
、明らかに)で速く失敗します。厳密に言えば、これはほとんど誤りではありません。明確な方法でサポートされていないことを伝えるだけです。通常、私は明示的な障害状態を賞賛しますが、これは(私が知る限り)文書化されておらず、単にパフォーマンスが低下する可能性がある状態で動作するアプリケーションではなく、完全に壊れたアプリケーションになります。
実際には、これが発生するのを目にしたのはstdioとやり取りするときだけです。ユーザーは、stdinまたはstdoutを通常のファイルとの間でリダイレクトする可能性があります。以前のstdinとstdoutはパイプでしたが、epollで問題なくサポートされていましたが、それは通常のファイルになり、epollは大規模に失敗してアプリケーションを破壊します。
man select
)Linuxカーネルは固定制限を課していませんが、glibcの実装により、fd_setは固定サイズタイプになり、FD_SETSIZEは1024として定義され、FD _ *()マクロはその限界。1023より大きいファイル記述子を監視するには、代わりにpoll(2)を使用します。CentOS 7では、カーネルがファイルハンドル> 1023を返したため、自分のコードがselect()に失敗する問題がすでにありました。現在、同じ問題にTwistedのような臭いがする問題を調べています。
私の会社でのテストでは、epoll()で1つの問題が発生したため、selectと比較して1つのコストが発生しました。
タイムアウトでネットワークから読み取ろうとする場合、(FD_SETの代わりに)epoll_fdを作成し、fdをepoll_fdに追加すると、FD_SET(単純なmalloc)を作成するよりもはるかにコストがかかります。
前の回答のとおり、プロセス内のFDの数が多くなると、select()のコストは高くなりますが、テストでは、10,000のfd値を使用した場合でも、selectが優勝しました。これらは、スレッドが待機しているfdが1つだけで、ブロッキングスレッドモデルを使用しているときに、ネットワークの読み取りとネットワークの書き込みがタイムアウトしないという事実を克服しようとしている場合です。もちろん、ブロッキングスレッドモデルは、ノンブロッキングリアクターシステムに比べてパフォーマンスは低くなりますが、特定のレガシーコードベースと統合するために必要になる場合があります。
リアクタモデルが毎回新しいepoll_fdを作成する必要がないため、この種の使用例は高性能アプリケーションではまれです。epoll_fdの寿命が長いモデルの場合---これは、あらゆる高性能サーバー設計に明らかに推奨されます--- epollは、あらゆる点で明らかに勝者です。
select()
ファイル記述子の値が10k以上の範囲にある場合は使用できません。システムの半分を再コンパイルしてFD_SETSIZEを変更しない限り、この戦略がどのように機能したのか疑問に思います。あなたが説明したシナリオについて、私はおそらくpoll()
どちらがそれよりselect()
もはるかに似ているかを見ますepoll()
が、FD_SETSIZEの制限が取り除かれています。
FD_SETSIZE
コンパイル時に設定されるコンパイル時定数です。アプリケーションのビルド時に別の値に定義すると、アプリケーションとCライブラリが一致せず、物事がうまくいきません。再定義しても安全だと主張する参考文献がある場合は、それらを参照してください。FD_SETSIZE
poll
完全性のためにの動作について明示することを検討してください。