Twistedでのselect / pollとepollリアクターの注意点


95

私が読んで経験したすべてのもの(トルネードベースのアプリ)は、eTollが特にTwistedでのSelectおよびPollベースのネットワーキングの自然な代替品であると私に信じさせます。それは私を偏執的にします、より良い技術または方法論が代償を伴わずに来るのはかなりまれです。

epollと代替案の間の数十の比較を読むと、epollは明らかに速度とスケーラビリティのチャンピオンであり、具体的には、それが素晴らしい線形の方法でスケーリングすることを示しています。とはいえ、プロセッサとメモリの使用率はどうですか?

回答:


190

ソケットの数が非常に少ない場合(もちろん、ハードウェアによって異なりますが、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をすべて使用する必要があるという事実を投入することもできselect1つのファイル記述子のみを監視したいが、その値が1024である場合、epollを使用すると、20バイトしか使用しません。それでも、これらの数値はすべて非常に小さいため、それほど大きな違いはありません。

また、epollには、FD_SETSIZEファイル記述子に限定されないという、おそらくすでにご存知のような他の利点もあります。これを使用して、必要な数のファイル記述子を監視できます。また、ファイル記述子が1つしかなく、その値がFD_SETSIZEより大きい場合、epollはそれでも機能しますが、select機能しません。

ランダムに、私も最近、1つのわずかな欠点を発見したepollと比較しselectたりpoll。一方でこれらの3つのAPIのどれも、通常のファイル(ファイルシステム上、すなわち、ファイル)をサポートしていない、selectpoll常に読みやすく、常に書き込み可能のような記述子を報告するように、支持の欠如を提示します。これにより、意味のある種​​類の非ブロッキングファイルシステムI / Oには不向きになります。ファイルシステムのファイル記述子を使用する、selectまたはpoll偶然に遭遇するプログラムは、少なくとも動作し続けます(または、失敗した場合、それは原因ではありません。のselectpoll)、それにもかかわらず、おそらくない最高の性能を持ちます。

一方、そのようなファイル記述子を監視するように要求された場合、epollはエラー(EPERM、明らかに)で速く失敗します。厳密に言えば、これはほとんど誤りではありません。明確な方法でサポートされていないことを伝えるだけです。通常、私は明示的な障害状態を賞賛しますが、これは(私が知る限り)文書化されておらず、単にパフォーマンスが低下する可能性がある状態で動作するアプリケーションではなく、完全に壊れたアプリケーションになります。

実際には、これが発生するのを目にしたのはstdioとやり取りするときだけです。ユーザーは、stdinまたはstdoutを通常のファイルとの間でリダイレクトする可能性があります。以前のstdinとstdoutはパイプでしたが、epollで問題なくサポートされていましたが、それは通常のファイルになり、epollは大規模に失敗してアプリケーションを破壊します。


とてもいい答えです。poll完全性のためにの動作について明示することを検討してください。
クォーク、

6
通常のファイルからの読み取りの動作に関する私の2セント:私は一般に、パフォーマンスの低下よりも完全な失敗を好みます。その理由は、開発中に検出される可能性がはるかに高いため、適切に回避されているためです(たとえば、実際のファイルに対してI / Oを実行する別の方法がある)。もちろんYMMV:顕著な減速は見られないかもしれません。その場合、失敗は良くありません。ただし、特別な場合にのみ発生する劇的な速度低下は、開発中に把握するのが非常に難しく、実際に展開されたときに時限爆弾として残されます。
クォーク

1
あなたの編集を完全に読まなければなりません。ある意味、私はepollが前任者を模倣しないことがおそらく正しくないことに同意しますが、EPERMエラーを実装した開発者が「常に壊れているからといって、上手。" さらに別の反論として、私は防御プログラマーであり、1 + 1を超えると疑わしいものであり、優雅な失敗を可能にするような方法でコーディングします。カーネルに予期しないエラーを発生させることは、良いことでも思いやりのあることでもありません。
David

1
@ Jean-Paul、kqueueについての説明も追加できますか?
Good Person

パフォーマンスを別にして、これに起因する問題はありますか(からman select)Linuxカーネルは固定制限を課していませんが、glibcの実装により、fd_setは固定サイズタイプになり、FD_SETSIZEは1024として定義され、FD _ *()マクロはその限界。1023より大きいファイル記述子を監視するには、代わりにpoll(2)を使用します。CentOS 7では、カーネルがファイルハンドル> 1023を返したため、自分のコードがselect()に失敗する問題がすでにありました。現在、同じ問題にTwistedのような臭いがする問題を調べています。
ポールDスミス

4

私の会社でのテストでは、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は、あらゆる点で明らかに勝者です。


5
ただし、select()ファイル記述子の値が10k以上の範囲にある場合は使用できません。システムの半分を再コンパイルしてFD_SETSIZEを変更しない限り、この戦略がどのように機能したのか疑問に思います。あなたが説明したシナリオについて、私はおそらくpoll()どちらがそれよりselect()もはるかに似ているかを見ますepoll()が、FD_SETSIZEの制限が取り除かれています。
Jean-Paul Calderone 14

FD_SETをmalloc()できるため、ファイル記述子の値が10Kの範囲にある場合は、select()を使用できます。実際、FD_SETSIZEはコンパイル時であり、実際のfd制限は実行時であるため、FD_SETを安全に使用するだけで、ファイル記述子の数がFD_SETのサイズと照合され、FD_SETが次の場合はmalloc(または道徳的に同等)が実行されます。小さすぎる。これをお客様と一緒に制作しているところを見てショックを受けました。20年間ソケットをプログラミングした後、私が書いたすべてのコード(およびWeb上のほとんどのチュートリアル)は安全ではありません。
Brian Bulkowski、2014年

5
これは、私の知る限り、人気のあるプラットフォームでは当てはまりません。 CライブラリのFD_SETSIZEコンパイル時に設定されるコンパイル時定数です。アプリケーションのビルド時に別の値に定義すると、アプリケーションとCライブラリが一致せず、物事がうまくいきません。再定義しても安全だと主張する参考文献がある場合は、それらを参照してください。FD_SETSIZE
Jean-Paul Calderone 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.