この記事は翻訳です。元のアドレス: https://stitcher.io/blog/fibers-with-a-gran-of-salt
Fibers with話は逸れます
そこで、PHP 8.1 でのファイバーの使用について詳細なブログ記事を書くつもりです。基本的な例から基礎から説明します。このアイデアは、非同期 HTTP リクエストを送信し、ファイバーを使用してそれらを並列処理することです。
しかし、いろいろいじってみると、RFC が「Fiber API はアプリケーション レベルのコードで直接使用すべきではない。Fibers は基本的な低レベルのフロー制御 API を提供する」と述べているのは冗談ではないことがわかりました。アプリケーション コードで使用される高レベルの抽象化を作成します。」
そこで、この道を進んで物事を複雑にする代わりに、ファイバーの概念とは何か、それがアプリケーション コードでほとんど利用できない理由、および非同期 PHP を正確に使用する方法について説明します。
まず、ちょっとした理論です。
3 つの HTTP リクエストを送信し、それらの結合結果を処理するとします。これを行う同期的な方法は、最初のメッセージを送信して応答を待ち、次に 2 番目のメッセージを送信して待機するという繰り返しです。
このようなプログラム フローを表すために、可能な限り単純な図を使用してみましょう。このグラフは上から下に読んでいき、時間を下に向かって読んでいく必要があります。各色は HTTP リクエストを表します。各リクエストの色付きの部分は、実際に実行されている PHP コード、サーバー上の CPU が作業を行っていることを表し、透明なブロックは待機時間を表します。リクエストはネットワーク経由で送信する必要があり、他のサーバーがそれを処理して送信する必要があります。応答が到着した場合にのみ、再び動作できるようになります。
これは、送信、待機、処理、繰り返しという同期実行プロセスです。
並列処理の世界では、リクエストを送信しますが、待機しません。次に、次のリクエストを送信し、さらに別のリクエストを送信します。その後、すべてのリクエストを待ちます。待っている間、リクエストの 1 つが完了したかどうかを定期的に確認します。このような場合でもすぐに対応させていただきます。
このアプローチでは待機時間をより最適に使用するため、実行時間がどのように短縮されるかがわかります。
ファイバーは、これらの並列実行パスをより効率的に管理できるようにする PHP 8.1 の新しいメカニズムです。発電機と を使用するとすでに収量が可能ですが、ファイバーはこのユースケース向けに特別に設計されているため、大幅な改善となります。
リクエストごとにファイバーを作成し、リクエストの送信後にファイバーを一時停止します。 3 つのファイバーをすべて作成したら、それらをループして 1 つずつ復元します。これにより、ファイバーはリクエストが完了したかどうかを確認し、完了していない場合は再び一時停止します。そうでない場合は、応答を処理して最終的に完了します。
ご存知のとおり、ファイバーは、プログラムの実行フローの分離された部分を開始、一時停止、再開するためのメカニズムです。ファイバーは「グリーン スレッド」とも呼ばれ、同じプロセス内に実際に存在するスレッドです。これらのスレッドはオペレーティング システムではなく、ランタイム (この場合は PHP ランタイム) によって管理されます。これらは、いくつかの形式の並列プログラミングを管理するためのコスト効率の高い方法です。
ただし、真の非同期的なものは何も追加されないことに注意してください。すべてのファイバーは同じ PHP プロセス内にあり、一度に 1 つのファイバーだけを実行できます。これは、イベントをループして待機中にチェックするメイン プロセスであり、このループは「イベント ループ」と呼ばれることがよくあります。
並列処理の難しい部分は、ファイバーやジェネレーター、または使用したいメカニズムをどのようにループするかということではありません。操作を開始し、外部サービスに渡して、チェックだけを実行できるかどうかです。ブロックしない方法で必要なときに結果を取得できます。
ほら、前の例では、リクエストを送信して、必要に応じてその応答をチェックできると想定していましたが、実際は思ったほど簡単ではありません。
その通りです。I/O を処理するほとんどの PHP 関数には、この種のノンブロッキング機能が組み込まれていません。実際、それを行う関数はほんのわずかであり、それらを使用するのは面倒です。
ノンブロッキングに設定できるソケットの例は次のとおりです。
[$read, $write] = stream_socket_pair( STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP ); stream_set_blocking($read, false); stream_set_blocking($write, false);
stream_socket_pair() を使用すると、双方向に使用できる 2 つのソケットが作成されます。コミュニケーション 。ご覧のとおり、stream_set_blocking() を使用してアクセスできます。
例を実装して、3 つのリクエストを送信するとします。これはソケットを使用して実行できますが、その上に HTTP プロトコルを独自に実装する必要があります。それはまさに nox7 がやったことです。ユーザーは、ファイバーとソケットを使用して HTTP GET リクエストを送信する方法を示す小さな概念実証を Reddit で共有しました。本当にアプリケーション コードでこれを実行しますか?
少なくとも私にとって、答えは「ノー」です。それはまさに RFC が警告していることです。私は気分を害しているわけではありません。代わりに、既存の非同期フレームワーク、Amp または ReactPHP のいずれかを使用することをお勧めします。
たとえば、ReactPHP を使用すると、次のように記述できます:
$loop = React\EventLoop\Factory::create(); $browser = new Clue\React\Buzz\Browser($loop); $promises = [ $browser->get('https://example.com/1'), $browser->get('https://example.com/2'), $browser->get('https://example.com/3'), ]; $responses = Block\awaitAll($promises, $loop);
与手动创建套接字连接相比,这是一个更好的示例。这就是 RFC 的意思:应用程序开发人员不需要担心纤程,它是 Amp 或 ReactPHP 等框架的实现细节。
不过,这给我们带来了一个问题:与我们已经可以用发电机做的事情相比,纤维有什么好处?RFC 是这样解释的:
与无堆栈生成器不同,每个 Fiber 都有自己的调用堆栈,允许它们在深度嵌套的函数调用中暂停。声明中断点的函数(即调用 Fiber::suspend())不需要更改其返回类型,这与使用 yield 的函数必须返回 Generator 实例不同。
Fiber 可以在任何函数调用中挂起,包括那些从 PHP VM 内部调用的函数,例如提供给 array_map 的函数或迭代器对象上的 foreach 调用的方法。
很明显,纤程在语法和灵活性方面都有显着的改进。但与 Go 及其“ goroutines ”相比,它们还不算什么。
要使异步 PHP 在没有框架开销的情况下成为主流,仍然缺少许多功能,而 Fiber 是朝着正确方向迈出的良好一步,但我们还没有做到这一点。
所以就是这样。如果您不是 Amp、ReactPHP 或较小的异步 PHP 框架的维护者,那么实际上没有什么可说的。也许更多的框架或库将开始合并它们?
同时,还有Swoole——一个 PHP 扩展,它实际上将几个核心功能修改为非阻塞。Swoole 本身是一个中文项目,在涉及英语时通常没有很好的文档记录,但最近 Laravel宣布与它进行第一方集成。也许这是将 PHP 推向更异步模型的更好策略:可选择将 Swoole 或其他扩展与 Laravel 和 Symfony 等框架集成?
以上がPHP8.1 の新機能の説明: ファイバーについての詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。