私が読んだ経験(Tornadoベースのアプリ)のすべてが、ePollがSelectおよびPollベースのネットワーキングの自然な代替品であると信じるようになりました。特にTwistedの場合です。それは私を妄想させます、より良い技術や方法論が価格に付属しないことはかなりまれです。
Epollと代替品の数十の比較を読むと、epollが明らかに速度とスケーラビリティのチャンピオンであることがわかります。具体的には、それが素晴らしい方法で線形にスケーリングされることを示しています。とはいえ、プロセッサとメモリの使用率についてはどうでしょうか、epollは依然としてチャンピオンですか?
ソケットの数が非常に少ない場合(もちろん、ハードウェアによって異なりますが、10個以下のオーダーについて話しています)、selectはメモリ使用量と実行速度の点で優れています。もちろん、このような少数のソケットの場合、両方のメカニズムは非常に高速であるため、ほとんどの場合、この違いはあまり気にしません。
ただし、説明が1つあります。 selectとepollは両方とも線形にスケーリングします。ただし、大きな違いは、ユーザー空間に面したAPIには、さまざまなことに基づいた複雑さがあります。 select
呼び出しのコストは、それを渡す最大番号のファイル記述子の値とほぼ同じです。単一のfd、100を選択する場合、単一のfd、50を選択する場合の約2倍の費用がかかります。最高以下のfdを追加することは完全に無料ではないため、実際にはこれよりも少し複雑です。ほとんどの実装に適した最初の近似です。
Epollのコストは、実際にイベントがあるファイル記述子の数に近くなります。 200個のファイル記述子を監視しているが、そのうちの100個だけがイベントを持っている場合、100個のアクティブなファイル記述子に対してのみ(非常に大雑把に)支払います。これは、epollがselectよりも大きな利点の1つを提供する傾向がある場所です。ほとんどがアイドル状態のクライアントが1,000個ある場合、selectを使用すると、それらすべてのクライアントに支払いが行われます。ただし、epollを使用すると、数個しか持っていないように見えます。その時点でアクティブになっているものに対してのみ料金を支払うことになります。
これはすべて、epollがほとんどのワークロードのCPU使用量を削減することを意味します。メモリ使用量に関する限り、それは少し投げられます。 select
は、非常にコンパクトな方法(ファイル記述子ごとに1ビット)で必要なすべての情報を表すことができます。また、select
で使用できるファイル記述子の数に関するFD_SETSIZE(通常1024)の制限は、select
(読み取り、書き込み、例外)で使用できる3つのfdセットのそれぞれに128バイトを超える時間を費やさないことを意味します。最大384バイトと比較すると、epollは一種の豚です。各ファイル記述子は、マルチバイト構造で表されます。ただし、絶対的に言えば、メモリをあまり使用しません。膨大な数のファイル記述子を数十キロバイトで表すことができます(1000個のファイル記述子ごとに約20k)。また、1つのファイル記述子のみを監視したいが、その値が1024である場合、それらのバイトの384個すべてをselect
で費やす必要があるという事実をスローすることができますが、epollでは20バイトしか消費しません。それでも、これらの数値はすべて非常に小さいため、それほど大きな違いはありません。
また、epollには他にも利点があります。おそらく既にご存知でしょうが、FD_SETSIZEファイル記述子に限定されないということです。これを使用して、できるだけ多くのファイル記述子を監視できます。また、ファイル記述子が1つしかなく、その値がFD_SETSIZEよりも大きい場合、epollはそれでも機能しますが、select
は機能しません。
ランダムに、最近、epoll
またはselect
と比較して、poll
にわずかな欠点があることも発見しました。これらの3つのAPIはいずれも通常のファイル(ファイルシステム上のファイル)をサポートしていませんが、select
およびpoll
は、このような記述子を常に読み取り可能および常に書き込み可能として報告するため、このサポートの欠如を示しています。これにより、意味のある種類のノンブロッキングファイルシステムI/Oには不向きになります。select
またはpoll
を使用し、ファイルシステムからファイル記述子に遭遇するプログラムは、少なくとも動作し続けます(または、失敗した場合は動作しません) select
またはpoll
が原因である可能性がありますが、おそらく最高のパフォーマンスではありません。
一方、epoll
は、このようなファイル記述子を監視するように要求された場合、エラー(明らかにEPERM
)で失敗します。厳密に言えば、これはほとんど間違いではありません。サポートの欠如を明示的な方法で単に通知しているだけです。通常、明示的な障害状態を称賛しますが、これは文書化されておらず(私の知る限り)、パフォーマンスが低下する可能性があるだけではなく、完全に壊れたアプリケーションになります。
実際には、これを目にした唯一の場所はstdioと対話するときです。ユーザーは、stdinまたはstdoutを通常のファイルとの間でリダイレクトする場合があります。以前はstdinとstdoutはパイプでしたが(epollで十分にサポートされていました)、通常のファイルになり、epollは大声で失敗し、アプリケーションが壊れます。
私の会社のテストでは、epoll()の問題が1つ発生したため、selectと比較して1つのコストがかかりました。
タイムアウトでネットワークからの読み取りを試行する場合、(FD_SETの代わりに)epoll_fdを作成し、epoll_fdにfdを追加すると、FD_SET(単純なmalloc)を作成するよりもはるかに費用がかかります。
前の回答によると、プロセス内のFDの数が多くなると、select()のコストは高くなりますが、テストでは、10,000のfd値であっても、selectが勝者でした。これらは、スレッドが待機しているfdが1つしかない場合で、ブロッキングスレッドモデルを使用すると、ネットワークの読み取りと書き込みがタイムアウトにならないという事実を克服しようとしています。もちろん、ブロッキングスレッドモデルは、ノンブロッキングリアクタシステムと比較してパフォーマンスは低くなりますが、特定のレガシーコードベースと統合するために必要な場合があります。
この種のユースケースは、高性能アプリケーションではまれです。これは、リアクタモデルが毎回新しいepoll_fdを作成する必要がないためです。 epoll_fdの寿命が長いモデルの場合---これは、高性能サーバー設計には明らかに好まれます--- epollは、あらゆる点で明確な勝者です。