#高い同時実行性に関しては、I/O 多重化をバイパスして特定のプラットフォームを指定する方法はありません。 Linux では、epoll をバイパスする方法はありません。epoll が効率的である理由については説明しません。興味のある学生は、自分で検索して学習してください。PHP で epoll を再生するにはどうすればよいですか?まず、libevent ライブラリをインストールし、次にイベント拡張機能または libevent 拡張機能をインストールする必要があります。そうすれば楽しくプレイできます。
libevent ライブラリと libevent 拡張機能の違いについて混乱している人もいます。簡単に言うと、 libevent ライブラリ これは C 言語での epoll のカプセル化であり、PHP とは何の関係もありません; libevent 拡張機能は、PHP と libevent ライブラリの間の通信ブリッジです。実際、PHP の多くの拡張機能がこれを行います。優れた C 言語ライブラリがいくつかあり、PHP がそれらを直接使用したい場合は、PHP 拡張機能を介して PHP に接続できます。libevent 拡張機能とイベント拡張機能のどちらかを選択します。個人的には、よりオブジェクト指向であるため、イベント拡張機能を好みます。 http://pecl.php.net にアクセスして、お使いの PHP バージョンに対応する拡張機能を検索し、ダウンロードし、コンパイルしてインストールすれば問題ありません。コンピューターにインストールされている複数のバージョンの PHP でコンパイルする場合は、次の点に注意してください。典型的な 5 つの手順は間違いありません:
phpize ./configure make make install php -m | grep event #看看装上了没
<?php use Event; use EventBase; class Reactor { protected $reactor; protected $events; public static $instance = null; const READ = Event::READ | Event::PERSIST; const WRITE = Event::WRITE | Event::PERSIST; public static function getInstance() { if (is_null(self::$instance)) { self::$instance = new self(); self::$instance->reactor = new EventBase; } return self::$instance; } public function add($fd, $what, $cb, $arg = null) { switch ($what) { case self::READ: $event = new Event($this->reactor, $fd, self::READ, $cb, $arg); break; case self::WRITE: $event = new Event($this->reactor, $fd, self::WRITE, $cb, $arg); break; default: $event = new Event($this->reactor, $fd, $what, $cb, $arg); break; } $event->add(); $this->events[(int) $fd][$what] = $event; } public function del($fd, $what = 'all') { $events = $this->events[(int) $fd]; if ($what == 'all') { foreach ($events as $event) { $event->free(); } } else { if ($what != self::READ && $what != self::WRITE) { throw new \Exception('不存在的事件'); } $events[$what]->free(); } } public function run() { $this->reactor->loop(); } public function stop() { foreach ($this->events as $events) { foreach ($events as $event) { $event->free(); } } $this->reactor->stop(); } }
<?php use Throwable;use Monolog\Handler\StreamHandler;class Server{ protected $ip; protected $port; protected $socket; protected $reactor; public function __construct($ip, $port) { $this->ip = $ip; $this->port = $port; } public function start() { $socket = $this->createTcpConnection(); stream_set_blocking($socket, false); Reactor::getInstance()->add($socket, Reactor::READ, function($socket) { $conn = stream_socket_accept($socket); stream_set_blocking($conn, false); (new Connection($conn))->handle(); }); Reactor::getInstance()->run(); } public function createTcpConnection() { $schema = sprintf("tcp://%s:%d", $this->ip, $this->port); $socket = stream_socket_server($schema, $errno, $errstr); if ($errno) { throw new \Exception($errstr); } return $socket; } }
<?phpclass Connection{ protected $conn; protected $read_buffer = ''; protected $write_buffer = ''; public function __construct($conn) { $this->conn = $conn; } public function handle() { Reactor::getInstance()->add($this->conn, Reactor::READ, \Closure::fromCallable([$this, 'read'])); } private function read($conn) { $this->read_buffer = ''; if (is_resource($conn)) { while ($content = fread($conn, 65535)) { $this->read_buffer .= $content; } } if ($this->read_buffer) { Reactor::getInstance()->add($conn, Reactor::WRITE, \Closure::fromCallable([$this, 'write'])); } else { Reactor::getInstance()->del($conn); fclose($conn); } } private function write($conn) { if (is_resource($conn)) { fwrite($conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=utf8\r\nContent-Length:11\r\nConnection: keep-alive\r\n\r\nHello!world"); } } }
stream_socket_accept を使用して新しい接続 Conn を受信し、Conn を Reactor に入れて読み取り可能なイベントを監視します。読み取り可能なイベントが発生した場合は、クライアントがデータが送信されます。データがなくなるまでループで読み取り、Reactor に Conn を入れて書き込み可能なイベントをリッスンします。書き込み可能なイベントが発生した場合、クライアント データが送信されたことを意味します。プロトコルを組み立てて応答を書き込みます。
ab を使用して同時実行性をテストし、
-k パラメーターを追加して接続を多重化します。i5 8G、3W では問題ありません同時実行性 (もちろん、ここにはありません。ディスク I/O、実際の状況では、ディスクからファイルを読み取り、Linux システム コールを介してファイルを読み取ります。また、いくつかのファイル コピー操作があり、比較的コストがかかります)。一般的な解決策は sendfile です。FD から直接別の FD にコピーする必要はありません。効率は比較的高いです。欠点は、PHP にはすぐに実装できる sendfile 拡張機能がないため、自分で行う必要があり、開発コストがかかることです。少し高いです。
これは、PHP で高同時実行サーバーを実装するというアイデアです。EPOLL で解決する限り、アイデアは同じです。これは 3 段階のプロセスです。それを Reactor の下に置いて監視します。 FDイベント。もちろん、これは最も単純なモデルであり、マルチプロセス、コピー nginx、1 つのメインプロセスと N 個のワーカープロセスなど、改善できる点はたくさんあります。マルチプロセスの目的は、マルチコアを使用することです。並行作業。同じことが C 言語の実装にも当てはまりますが、libevent ライブラリを使用して EPOLL を自分でカプセル化することはできません。結局のところ、libevent ライブラリは少し重いため、libevent では多くの機能が使用できません。もちろん C 言語は必要ありません。大量のデータ構造とそのデータ構造上で定義された関数がある オペレーションを記述する必要がある、GC がない、メモリを自分で管理する必要がある、適切な設計が必要である 複数のプロセスを実行する場合、作業が必要IPCのプロセス間通信については、PHPに比べて開発難易度が高く、開発サイクルも非常に長いので、興味があれば学生一人でも遊んでみてはいかがでしょうか。
PHP 関連の技術記事の詳細については、PHP チュートリアル 列にアクセスして学習してください。
以上がPHP を使用した高同時実行サーバーの実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。