Java での IO 再利用の詳細な図とテキストの説明

黄舟
リリース: 2017-05-28 09:23:00
オリジナル
1426 人が閲覧しました

この記事は主に Java IO 再利用に関する関連知識を紹介するものであり、非常に優れており、必要な方は参考にしてください。

サーバーの

同時処理機能については、次のものが必要です。このミリ秒以内に数百の異なる TCP 接続で受信されたすべてのメッセージは、タイムリーに処理できます。同時に、サーバー上には、メッセージの送受信が行われていない数十万の比較的非アクティブな接続が存在する可能性があります。ここ数秒で。同時に並行して発生する複数の接続を処理することを、略して同時実行性と呼びます。数万または数十万の接続を同時に処理することを高同時実行性と呼びます。サーバーの同時実行性プログラミングが追求するのは、物理リソースが最初に使い果たされるまで、CPU などのリソースの効率的な使用を維持しながら、無限数の同時接続を処理することです。 同時プログラミングモデル

には多くの実装があり、最も単純なものは「スレッド」にバンドルされており、1つのスレッドが1つの接続の

ライフサイクル全体を処理します。利点: このモデルは非常にシンプルで、複雑なビジネス シナリオを実装でき、同時にスレッドの数が CPU の数よりもはるかに多くなる可能性があります。しかし、スレッド数は無限に増やすことができないのはなぜでしょうか。スレッドがいつ実行されるかはオペレーティング システムのカーネル スケジューリング アルゴリズムによって決定されるため、スケジューリング アルゴリズムでは、特定のスレッドが 1 つの接続のみを処理できることは考慮されません。統一されたゲームプレイが採用されます。たとえタイム スライスが終了した場合でもスレッドを実行します。このスレッドを実行すると、スリープを続ける必要があります。このスレッドのウェイクアップとスリープの往復は、回数が少ない場合は安価ですが、オペレーティング システム内のスレッドの総数が多い場合は、この技術的なスケジューリングの損失がスレッドに影響を与えるため、コストが高くなります (増幅されます)。ビジネスコードが実行される時刻。たとえば、現時点で非アクティブな接続を持つスレッドのほとんどは、実行効率が低すぎるため、起動して CPU リソースを奪い合います。これは、アクティブな接続を処理するプライベート エンタープライズ スレッドの数が減少し、CPU を獲得する機会が減少することを意味します。CPU は競争力の中心であり、その非効率性は総 GDP スループットに影響します。私たちが追求しているのは、数十万の接続を同時に処理することです。数千のスレッドが出現すると、システムの実行効率は高い同時実行性を満たせなくなります。 同時実行性の高いプログラミングには、現在モデルが 1 つだけあり、それが本質的に唯一の効果的な方法です。接続上のメッセージ処理は、メッセージの準備ができるまで待機する段階とメッセージの処理という 2 つの段階に分けることができます。デフォルトのブロッキング ソケット (たとえば、前述の 1 つの接続を処理するためにバンドルされた 1 つのスレッド) を使用する場合、これら 2 つのステージは 1 つに結合されることが多いため、ソケット コードを操作するスレッドはメッセージの準備ができるまでスリープする必要があります。これにより、同時実行性が高い状態ではスレッドが頻繁にスリープおよびウェイクアップするため、CPU 使用効率に影響します。

同時実行性の高いプログラミング方法では、当然のことながら 2 つの段階を分離します。つまり、メッセージの準備ができるまで待機するコード セクションが、メッセージを処理するコード セクションから分離されます。もちろん、これにはソケットが非ブロッキングである必要もあります。そうでない場合、条件が満たされない場合、メッセージを処理するコード セグメントによってスレッドが簡単にスリープ待機段階に入る可能性があります。そこで問題は、メッセージの準備が完了するのを待つこの段階をどのように達成するかということです。結局のところ、まだ待機中です。つまり、スレッドはまだスリープ状態でなければなりません。解決策は、積極的に

クエリ

を実行するか、1 つのスレッドがすべての接続を待機するようにすることです。これがIO多重化です。多重化はメッセージの準備ができるのを待つことですが、複数の接続を同時に処理できます。 「待機」することもできるため、スレッドがスリープ状態になる可能性もありますが、1 対多であり、すべての接続を監視できるため、これは問題ではありません。このようにして、スレッドが実行のために起動されると、コードによって実行される準備ができている接続がいくつか存在する必要があり、これは効率的です。 「メッセージの準備ができるのを待っている」フェーズの処理を競合するスレッドはそれほど多くなく、ついに全世界が明らかになりました。

linux では、2.4 カーネル以前では、主に select と poll が実装されていましたが、その使用方法は大きく異なっているように見えますが、本質は同じです。
効率も異なるため、epoll は select を完全に置き換えました。 epoll が select を置き換える理由について簡単に説明しましょう。

前述したように、高い同時実行性を実現するための中心的な解決策は、すべての接続に対して 1 つのスレッドで「メッセージの準備ができるまで待機」することです。この点では、epoll と select には議論の余地がありません。しかし、記事の冒頭で述べたように、数十万の同時接続が存在する場合、アクティブな接続は 1 ミリ秒あたり数百しかなく、残りの数十万の接続はアクティブである可能性があります。このミリ秒間は非アクティブです。 select の使用方法は次のとおりです:

返されたアクティブな接続 ==select (監視対象のすべての接続)

select メソッドはいつ呼び出されますか?パケットが到着したアクティブな接続を確認する必要があると考えられる場合は、これを呼び出す必要があります。したがって、同時実行性が高い場合、select の呼び出しは頻繁に呼び出されます。このように、この頻繁に呼び出されるメソッドが効率的であるかどうかを確認する必要があります。なぜなら、そのわずかな効率の低下が「頻繁」という言葉によって増幅されるからです。効率が低下することはありますか?明らかに、監視対象の接続は数十万件ありますが、返されるアクティブな接続は数百件のみであり、それ自体が非効率です。強化された後、select は数万の同時接続をまったく処理できないことがわかります。 いくつかの写真を見てください。同時接続数が 1,000 未満の場合、select の実行回数はそれほど多くなく、epoll と大きな違いはないようです:

しかし、同時接続数が増加すると、 select の欠点は、「頻繁な実行」によって無限に拡大され、同時実行性が高くなるほど、それがより明らかになります:


epoll がそれをどのように解決するかについて話しましょう。 select メソッドの機能を実現するために 3 つのメソッドを巧みに使用しています:


新しい epoll 記述子==epoll_create()

epoll_ctrl (epoll 記述子、監視対象のすべての接続を追加または

削除)

返されたアクティブな接続 == epoll_wait (epoll 記述子)

これを行う主な利点は、頻繁に呼び出される操作とあまり呼び出されない操作を区別できることです。たとえば、epoll_ctrl はそれほど頻繁には呼び出されませんが、epoll_wait は非常に頻繁に呼び出されます。現時点では、epoll_wait には入力パラメーターがほとんどなく、select よりもはるかに効率的です。また、同時接続が増加しても入力パラメーターの数が増加することはなく、カーネルの実行効率が低下します。


epoll はどのように実装されていますか?実際、これらの 3 つのメソッドは、epoll_wait が頻繁に呼び出すたびに監視対象のすべての接続を渡す必要を回避する点で、select よりも賢明であることがわかります。ステージ」の。これは、監視対象のすべての接続を保存するためにカーネル モードでデータ構造を維持することを意味します。このデータ構造は赤黒ツリーであり、そのノードの追加と削減は epoll_ctrl によって完了します。それは非常に簡単です:


写真の左下にある赤と黒のツリーは、監視されるすべての接続で構成されています。左上のリンクされたリストには、現在アクティブなすべての接続が表示されます。したがって、epoll_wait が実行されると、左上のリンク リストのみがチェックされ、左上のリンク リスト内の接続がユーザーに返されます。このように、epoll_waitの実行効率は低いのではないでしょうか?

最後に、epoll が提供する 2 つのゲームプレイ メソッド ET と LT、つまり翻訳されたエッジ トリガーと水平トリガーを見てみましょう。実際、これら 2 つの中国語名はある程度適切です。これら 2 つの使用方法は依然として効率の問題を目的としていますが、単に epoll_wait によって返される接続をより正確にする方法になります。

たとえば、接続の書き込みバッファが空いているかどうかを監視する必要があります。「書き込み可能」の場合は、ユーザー モードからクライアントに write という応答を送信できます。ただし、接続が書き込み可能な場合、「応答」コンテンツはまだディスク上にある可能性があります。この時点でディスクの読み取りが完了していない場合はどうなるでしょうか。スレッドをブロックしてはいけないため、応答は送信されません。ただし、次回 epoll_wait を実行したときに接続が返される可能性があるため、それを処理するかどうかを確認する必要があります。おそらく、プログラムにはディスク IO を特別に処理する別のモジュールがあり、ディスク IO が完了すると応答が送信されます。それでは、epoll_wait がすぐに処理できないこの「書き込み可能な」接続を返すたびに、それはユーザーの期待に応えているのでしょうか?


そこで、ET モードと LT モードが登場しました。 LT は、期待される

state を満たすすべての接続が epoll_wait で返される必要があるため、全員を平等に扱い、水平線上にあります。これは、より正確なリターン接続を好む ET には当てはまりません。上記の例では、接続が初めて書き込み可能になった後、プログラムが接続にデータを書き込まない場合、次回 epoll_wait は接続を返しません。 ET はエッジ トリガーと呼ばれます。これは、接続がある状態から別の状態に変化した場合にのみ epoll_wait がトリガーされて返されることを意味します。 ET のプログラミングははるかに複雑であることがわかります。少なくともアプリケーションは、epoll_wait によって返される接続が表示されないように注意する必要があります。書き込み可能な場合、データは書き込まれませんが、次の「書き込み可能」を期待します。読み取り可能な場合、データは読み取られませんが、次回は「読み取り可能」になることを期待します。

もちろん、一般的なアプリケーション シナリオでは、両者の間にパフォーマンスに大きな違いはありません。ET の利点として考えられるのは、epoll_wait の呼び出し回数が減り、シナリオによっては接続が解除されないことです。は必要ありません (このウェイクアップは epoll_wait リターンを指します)。しかし、上で述べた例のような場合は、単なるネットワークの問題ではなく、アプリケーション シナリオに関連している場合があります。もちろん、ほとんどのオープンソースフレームワークはETに基づいて書かれており、フレームワークに関しては純粋に技術的な問題を追求し、もちろん完璧を目指しています

以上がJava での IO 再利用の詳細な図とテキストの説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!