ホームページ  >  記事  >  バックエンド開発  >  PHP 同時 IO プログラミングの詳細な説明

PHP 同時 IO プログラミングの詳細な説明

小云云
小云云オリジナル
2018-03-22 09:15:131867ブラウズ

同時実行性 IO この問題は、初期の同期ブロッキング ダイレクト Fork プロセスからワーカー プロセス プール/スレッド プール、現在の非同期 IO とコルーチンに至るまで、サーバーサイド プログラミングにおける常に技術的な問題です。 PHP プログラマーはその強力な機能により、 LAMP フレームワークは、そのような基本的な側面についてほとんど知識がありません。この記事の目的は、同時 IO プログラミングにおける PHP のさまざまな試みを詳細に紹介し、最後に同時 IO の問題を包括的に分析するための Swoole の使用をシンプルかつ分かりやすく紹介することです。条項。

multi-process/multi-thread同期ブロッキング。プロセス モデルは最も早くに登場し、プロセスの概念は

Unix システムの誕生以来存在しています。 最も初期のサーバー側プログラムは一般に Accept クライアント接続ごとにプロセスが作成され、子プロセスはループに入り、同期的かつブロック的な方法でクライアント接続と対話し、送信と受信を行います。データを処理しています。 マルチスレッド モードは後で登場し、スレッドはプロセスよりも軽量であり、メモリ スタックがスレッド間で共有されるため、異なるスレッド間の対話は非常に簡単に実装できます。たとえば、チャット ルームのようなプログラムでは、クライアント接続は相互に対話でき、チャット ルーム内のプレーヤーは他の人にメッセージを送信できます。マルチスレッド モードでの実装は非常に簡単で、スレッド内のクライアント接続にデータを直接送信できます。マルチプロセス モードでは、パイプライン、メッセージ キュー、共有メモリなどの複雑なテクノロジを使用する必要があり、これらを総称してプロセス間通信 (IPC

) と呼びます。

コード例: マルチプロセス

/

スレッドモデルのプロセスは

  1. ソケットを作成し、でサーバーポートをバインドし(bind)、ポートでリッスンします(listen)。 PHP中国語では stream_socket_server 1 つの関数で上記の 3 の手順を完了できます。 もちろん、下位レベルのソケット の拡張機能を使用して個別に実装することもできます。

  2. whileループに入り、accept操作をブロックし、クライアント接続が入るのを待ちます。このとき、プログラムは、新しいクライアントがサーバーへの接続を開始するまでスリープ状態に入り、オペレーティングシステムがこのプロセスを起動します。 accept関数は、クライアントが接続したsocket

  3. を返します。メインプロセスは
  4. forkを渡します() php: pcntl_fork) 子プロセスを作成するには、pthread_create(php: new Thread) は子スレッドを作成します。以下で特に明記されていない限り、process はプロセス/スレッドを表すためにも使用されます。

  5. 子プロセスが正常に作成されると、whileループに入り、recv(php: fread) を呼び出し、クライアントがサーバーにデータを送信するのを待ちます。データを受信した後、サーバー プログラムはそれを処理し、send (php: fwrite) はクライアントに応答を送信します。接続時間が長いサービスはクライアントとの対話を継続しますが、接続時間が短いサービスは通常、応答を受信した後に終了します。 クライアント接続が閉じられると、子プロセスが終了し、すべてのリソースが破棄されます。メインプロセスはこの子プロセスをリサイクルします。

  6. このモデルの最大の問題は、

  7. /

スレッドの作成と破棄のプロセスに非常にコストがかかることです。したがって、上記のモデルは非常に負荷の高いサーバー プログラムには適用できません。対応する改良版はこの問題を解決します。これは古典的な リーダー-フォロワー モデルです。 コード例:

その特徴は、プログラムの開始後に

N

のプロセスを作成することです。各子プロセスは Accept に入り、新しい接続が入るのを待ちます。クライアントがサーバーに接続すると、子プロセスの 1 つが起動され、クライアント要求の処理が開始され、新しい TCP 接続は受け入れられなくなります。この接続が閉じられると、子プロセスは解放され、新しい接続の処理に参加するために同意してに入ります。

このモデルの利点は、プロセスを完全に再利用でき、追加の消費がなく、非常に優れたパフォーマンスが得られることです。 ApachePHP-FPMなど、多くの一般的なサーバープログラムはこのモデルに基づいています。

マルチプロセス モデルにはいくつかの欠点もあります。

  1. このモデルは、同時実行性の問題を解決するためにプロセスの数に大きく依存しており、1 つのクライアント接続に必要なワーカー プロセスの数は同時処理能力に依存します。オペレーティング システムが作成できるプロセスの数には制限があります。

  2. 多数のプロセスを開始すると、追加のプロセス スケジューリングの消費が発生します。数百のプロセスがある場合、プロセス コンテキスト切り替えスケジューリングの消費量は CPU 1% 未満である可能性があり、数千、さらには数万のプロセスが開始される場合は無視できます。消費が急増するでしょう。スケジュールの消費量は、CPUの数十パーセント、あるいは100%を占める可能性があります。

  3. インスタント チャット プログラム (

IM) など、サーバーが数万、場合によっては数十万、数百万を維持する必要がある、マルチプロセス モデルでは解決できないシナリオもいくつかあります。同時に接続できる数が多い場合 (古典的な C10K 問題)、マルチプロセス モデルでは不十分です。

マルチプロセス モデルの弱点でもある別のシナリオがあります。通常、Webサーバーは、1つのリクエストが100ms100プロセスを消費する場合、100プロセスを開始します1000qpsを提供できます、これ処理能力はまだ良いです。ただし、リクエストで外部ネットワーク Http インターフェイス (QQ、Weibo ログインなど) を呼び出す必要がある場合は、長い時間がかかり、1 つのリクエストには 10 秒 かかります。 。その 1 つのプロセスは 0.1 リクエストを 1 秒でしか処理できず、100 プロセスは 10qps しか処理できません。 、こんな感じで処理能力はあまりにも悪い。

すべての同時実行IOを1つのプロセスで処理できるテクノロジーはありますか?答えは「はい」です。これは IO 多重化テクノロジーです。

IO再利用/イベントループ/非同期ノンブロッキング

実際IO 再利用の歴史は複数あるLinuxは、プロセス内の1024接続を維持できるselectシステムコールを長い間提供してきました。その後、pollシステムコールが追加され、pollはいくつかの改良を加え、1024制限の問題を解決し、任意の数の接続を維持できるようになりました。しかし、select/pollのもう1つの問題は、接続上にイベントがあるかどうかを検出するためにループする必要があることです。ここで問題が発生します。サーバーに1億の接続があり、特定の時間にサーバーにデータを送信する接続が1つだけである場合、select/pollはループを実行する必要があります 1001万回のうち、1回のみがヒットし、残りの99million9999回はすべて無効でしたテッド CPU リソース

U

linux 2.6 まで カーネルは、無制限の接続を維持できる新しい EPOLL システムコールを提供しており、問い合わせる必要はありません。現在、Nginx アーランゴランNode.js のようなシングルプロセスおよびシングルスレッドプログラムは、epoll のおかげで、1millionTCPを超える接続を維持できます。 テクノロジー。 IO古典的なReactorモデル、Reactorを使用して、名前が示すように、リアクター自体。送受信されるデータ。

socket

ハンドルのイベントの変更を監視するだけです。 Reactorには4のコアオペレーションがあります:

  1. addaddsocketlisten to reactor、これはlistenすることができます ソケット使用は、クライアントSocketを作成することもできますし、パイプライン、Eventfd、シグナルなどの変更イベント監視型、読み取り可能および書き込み可能などのタイプにすることもできます。読みやすくてわかりやすいので、聞いてください Socket

  2. は、新しいクライアントが接続するときに
  3. accept が必要であることを意味します。クライアント接続がデータを受信するには、recvが必要です。書き込み可能なイベントは、理解するのが少し難しくなります。 SOCKETにはキャッシュ領域があります。2Mデータをクライアント接続に送信したい場合、オペレーティングシステムのデフォルトではTCPになります。 キャッシング このエリアには256Kしかありません。一度に送信できるのは 256K だけです。キャッシュがいっぱいの場合、sendEAGAIN エラーを返します。現時点では、書き込み可能なイベントを監視する必要があります。純粋な非同期プログラミングでは、send操作が完全にノンブロッキングであることを確認する必要があります。 delreactor

  4. から削除され、イベントをリッスンしなくなりました
  5. callbackはイベント発生後の対応する処理ロジックで、通常はadd/setの際に定式化されます。 C言語は関数ポインタで実装されており、JSは匿名関数を使用でき、PHPは匿名関数、オブジェクトメソッド配列、および文字列関数名を使用できます。


Reactorは、socketハンドル上で実際に動作する単なるイベントジェネレーターです(connect/accept送信/ recv closecallbackで行われます。具体的なコーディングについては、以下の疑似コードを参照してください:

Reactorこのモデルは、マルチプロセスおよびマルチスレッドと組み合わせて、非同期ノンブロッキングを実現することもできますIO マルチコアを利用します。現在人気のある非同期サーバー プログラムはすべて次のようなものです:

  • Nginx: マルチプロセス Reactor

  • Nginx+Lua : マルチ-プロセス Reactor+Coroutine

  • Golang: シングルスレッド Reactor+マルチスレッドコルーチン

  • Swoole: マルチスレッドReactor+マルチプロセスワーカー

コルーチンとは

基礎となるテクノロジーの観点から見ると、コルーチンは実際には非同期ですIO Reactor モデルでは、アプリケーション層がタスク スケジューリングを独自に実装し、Reactor を使用して現在実行中の各ユーザー モード スレッドを切り替えますが、Reactor の存在はユーザー コードではまったく見えません。


PHP同時IOプログラミングの実践

PHP関連拡張子

  • ストリーム: PHP カーネルソケットパッケージが提供されています

  • Sockets: 基礎となるソケット用 API のカプセル化

  • Libevent: libeventライブラリのカプセル化

  • イベント : Libeventに基づいて更新されましたカプセル化、オブジェクト指向のインターフェイス、タイマー、および信号処理のサポートを提供する

  • pcntl/posix:複数のプロセス、シグナル、およびプロセス管理のサポート: マルチスレッド、スレッド管理、ロックのサポート

  • PHP共有メモリ、セマフォ、メッセージキューの関連拡張機能もあります

  • PECL: PHP拡張ライブラリ。システムの最下層、データ分析、アルゴリズム、ドライバー、科学技術計算、グラフィックスなどが含まれます。 PHP標準ライブラリに見つからない場合は、PECLで目的の関数を見つけることができます。

PHP 言語の利点と欠点

PHP の利点:

  1. 最初のものは簡単です、 PHPよりその他 PHP を使い始めたい場合は、言語が単純である必要があります。実際には 1 週間で始めることができます。 C++21Days of Deep LearningC++』という本がありますが、実は21で学ぶことは不可能です。 C++ 3-5年を経ないと、それを深くマスターすることは不可能です。しかし、PHP7から確実に始めることができます。つまり PHP プログラマーの数が非常に多く、他の言語に比べて採用が簡単です。

  2. PHPの公式標準ライブラリと拡張ライブラリPHPは、サーバープログラミングに使用できるものの99%を提供しているため、非常に強力です。 PHPPECL拡張ライブラリには、必要な機能がすべて揃っています。

さらに、PHPのエコシステムは非常に大きく、Githubで見つけることができます。 コード。 PHP

の欠点: 結局のところ動的スクリプトであるため、同じ

    PHPプログラムを使用する場合、パフォーマンスが比較的低く、集中的な操作には適していません。中古
  1. C/C++ で書かれているため、PHP バージョンはそれよりも 100 倍悪いです。 関数の命名規則が貧弱であることは誰もが知っていますPHP

  2. には実用性が重視されており、いくつかの仕様がありません。一部の関数の名前は非常にわかりにくいため、毎回
  3. PHP のマニュアルを参照する必要があります。

  4. 提供されるデータ構造と関数のインターフェイスの粒度は比較的粗いです。 PHPにはArrayデータ構造が1つだけあり、基礎となる層はHashTableに基づいています。 PHPArrayは、MapSetを設定しますベクトルキュー StackHeapおよびその他のデータ構造関数。さらに、PHPには、他のデータ構造のクラスカプセル化を提供するSPLがあります。

そのため、PHP

  1. PHPは、実用的なアプリケーションレベルのプログラム、ビジネス開発、および迅速な実装ツールに適しています

  2. PHP には適しません低レベル開発 ソフトウェア

  3. は、PHP の補足として、C/C++JAVAGolang およびその他の静的コンパイル言語を使用します。 、組み合わせる静的および動的

  4. ヘルプ付き IDE自動補完と文法プロンプトのためのツール


上記の拡張機能に基づいた

PHP

Swoole 拡張機能は、純粋な PHP を使用して非同期ネットワーク サーバーとクライアント プログラムを完全に実装できます。しかし、複数の IO に似たスレッドを実装したい場合は、接続の管理方法、データ送受信のアトミック性の確保方法、ネットワークなど、やるべき退屈なプログラミング作業がまだたくさんあります。プロトコル処理。また、PHPコードのプロトコル処理部分のパフォーマンスが比較的悪いため、C言語とを使用した新しいオープンソースプロジェクトSwooleを開始しましたPHP を組み合わせて仕事を完了します。柔軟で変更可能なビジネスモジュールはPHPを使用して高い開発効率を実現し、基本的な基盤部分とプロトコル処理部分はC言語で実装されており、高いパフォーマンスを保証します。これは拡張された方法で PHP にロードされ、完全なネットワーク通信フレームワークを提供し、その後、PHP コードを使用して何らかのビジネスを記述することができます。そのモデルはマルチスレッドReactor+マルチプロセスWorkerに基づいており、完全な非同期と半非同期と準同期の両方をサポートします。

Swooleのいくつかの機能:

  • スレッドを受け入れ、パフォーマンスのボトルネックと雷を散らす群れの問題を解決します 複数の

  • IO
  • スレッド、はいマルチコアを有効活用する 完全非同期、半同期、半非同期を提供

  • 2
  • モード 高い同時実行性を処理

  • IO
  • 部分を非同期モードで処理 複雑なビジネスロジック 部分的に同期モードを使用

  • 最下層は、すべての接続の横断、データの相互送信、データ パケットの自動的なマージと分割、およびデータのアトミック送信をサポートします。

Swoole プロセス/ スレッドモデル:

Swoole プログラム実行フロー:

PHP+Swooleを使用する拡張実装非同期通信プログラミングの概要

サンプル コードは、https://github.com/swoole/swoole-src ホームページでご覧いただけます。

TCPサーバーとクライアント

非同期TCPサーバー:

こちら Woole_server オブジェクトにアクセスし、パラメータがリスニングに渡されます。 HOSTPORT を設定し、新しい接続が来たときの onConnect コールバック関数を設定しますで、 受信時 特定のクライアントからデータを受信しました、onClose 特定のクライアントが接続を閉じました。最後に start を呼び出してサーバー プログラムを開始します。 swoole最下層は、CPUコアの数に基づいて、対応する数のReactorスレッドとWorkerを開始します現在のマシンには プロセスがあります。 。

非同期クライアント:

クライアントは、4コールバックイベント、onConnectがあることを除いてサーバーと似ています。サーバーに接続されました。データをサーバーに送信します。 onErrorサーバーに接続できませんでした。 onReceiveサーバーはクライアント接続にデータを送信しました。 onClose接続が閉じられました。

イベントコールバックを設定した後、サーバーへのconnectを開始します。パラメータはサーバーのIP、PORTです。

同期クライアント:

同期クライアントはイベントコールバックを設定する必要がなく、Reactorモニタリングを持っていませんシリアル。次のステップに進む前に、IOが完了するまで待ちます。

非同期タスク:

非同期タスク関数は、純粋に非同期の Server プログラムで時間のかかる関数またはブロック関数を実行するために使用されます。基盤となる実装ではプロセス プールを使用し、タスクが完了すると onFinish がトリガーされ、プログラム内でタスクの処理結果を取得できます。たとえば、IMを非同期コードで直接ブロードキャストする場合、他のイベントの処理に影響を与える可能性があります。また、Reactorを使用したsocketのようにファイルハンドルを監視できないため、非同期タスクを使用してファイルの読み書きを実装することもできます。ファイル ハンドルは常に読み取り可能なため、ファイルを直接読み取るとサーバー プログラムがブロックされる可能性があります。非同期タスクを使用することは非常に良い選択です。

非同期ミリ秒タイマー

この2インターフェースは次のようなものを実装しますJS setIntervalsetTimeout関数 function は、nミリ秒間隔で関数を実装するか、nミリ秒後に関数を実行するように設定できます。

非同期MySQLクライアント

swooleは、MySQL非同期クライアント用の組み込み接続プールも提供しており、MySQL接続の最大数を設定できます。同時の SQL リクエストは、これらの接続を繰り返し作成する代わりに再利用できるため、MySQL が接続リソースの枯渇から保護されます。

非同期Redisクライアント

非同期 ウェブプログラム

ロジックプログラムの内容は、Redisからデータを読み取り、HTMLページを表示することです。 abを使用したスト​​レステストのパフォーマンスは次のとおりです:

php-fpmでの同じロジックによるパフォーマンステストの結果は次のとおりです:

WebSocketプログラム

swooleにはwebsocketサーバーが組み込まれており、WebIMなどのWebページのアクティブプッシュ機能を実装するために使用できます。 。参考として使用できるオープンソース プロジェクトがあります。 https://github.com/matyhtf/php-webim

PHP+SwooleCoroutine

非同期プログラミングでは、通常、非常に複雑なロジックに遭遇した場合、コールバック関数をネストすることがあります。層ごとに。コルーチンはこの問題を解決できます。コードはシーケンシャルに記述できますが、ランタイムは非同期でノンブロッキングです。 Tencent のエンジニアは、Swoole拡張機能とPHP5.5Yield/Generator構文の実装に基づいており、Golangに似ています コルーチン、プロジェクト名TSF(テンセント) Server Framework)、オープンソース プロジェクトのアドレス: https://github.com/tencent-php/tsf。現在、テンセントの企業QQQQ公式アカウントプロジェクト、およびハンドル無視交通違反チェックプロジェクトに大規模なアプリケーションが導入されています。 。

TSF も非常に簡単に使用できます。これは完全にシリアルな 3 オペレーションを呼び出します。しかし、実際には非同期かつノンブロックで実行されます。 TSF 基礎となるスケジューラはプログラムの実行を引き継ぎ、対応するIOが完了した後も実行を継続します。

以上がPHP 同時 IO プログラミングの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。