Home >Backend Development >PHP8 >PHP8.1 new features explained: Fibers with a grain of salt
This article is a translation, original address: https://stitcher.io/blog/fibers-with-a-grain-of-salt
Fibers with a grain of salt
So I'm going to write an in-depth blog post about using Fibers in PHP 8.1. We'll explain them from the ground up, starting with a basic example. The idea is to send asynchronous HTTP requests and process them in parallel using fibers.
But playing around with them, I learned that the RFC wasn't kidding when it said "The Fiber API should not be used directly in application-level code. Fibers provides a basic, low-level flow control API to create higher-level abstractions that are then used in application code."
So instead of going this route and overcomplicating things, we'll discuss what fiber concepts are, why they're barely available in application code, and how exactly you can use asynchronous PHP.
First, a little theory.
Suppose you want to send three HTTP requests and process their combined results. The synchronous way of doing this is to send the first one, wait for a response, then send the second one, wait, and so on.
Let us use the simplest possible diagram to represent such a program flow. You need to read this chart from top to bottom, with time going further down. Each color represents an HTTP request. The colored portion of each request represents the actual PHP code running, the CPU on your server doing the work, and the transparent block represents the waiting time: the request needs to be sent over the network, and other servers need to process it and send it back. Only when the response arrives can we Works again.
This is a synchronous execution process: send, wait, process, repeat.
In the world of parallel processing, we send requests but don't wait. Then we send the next request, and then another. Only then we wait for all requests. While waiting, we periodically check to see if one of our requests has completed. If this is the case, we can handle it immediately.
You can see how this approach reduces the execution time because we use the wait time more optimally.
Fibers are a new mechanism in PHP 8.1 that allow you to manage these parallel execution paths more efficiently. Yield is already possible using generators and , but fibers are a significant improvement as they are specifically designed for this use case.
You will create a fiber for each request and pause the fiber after the request is sent. After creating all three fibers, you will loop through them and restore them one by one. By doing this, the fiber checks if the request has completed and pauses again if not, otherwise it can process the response and eventually complete.
You see, a fiber is a mechanism for starting, pausing, and resuming isolated portions of a program's execution flow. Fiber is also known as a "green thread": a thread that actually exists within the same process. These threads are not managed by the operating system, but by the runtime - in our case the PHP runtime. They are a cost-effective way to manage some forms of parallel programming.
But note that they don't add anything truly asynchronous: all fibers are in the same PHP process, and only one fiber can be running at a time. This is the main process that loops through them and checks them while waiting, this loop is often called the "event loop".
The hard part about parallelism isn't how you loop over fibers or generators, or whatever mechanism you want to use; it's about being able to start an operation, hand it off to an external service, and only Check the results when you want in a non-blocking way.
Look, in the previous example we assumed we could just send a request and then check for its response when we wanted to, but that's actually not as easy as it sounds.
That's right: most PHP functions that handle I/O don't have this kind of non-blocking functionality built in. In fact, only a few functions do it, and using them is cumbersome.
There is an example of a socket that can be set to non-blocking, like this:
[$read, $write] = stream_socket_pair( STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP ); stream_set_blocking($read, false); stream_set_blocking($write, false);
By using stream_socket_pair(), two sockets are created that can be used for two-way communication . As you can see, they can be accessed using stream_set_blocking().
Suppose we want to implement our example, sending three requests. We can do this using sockets, but we need to implement the HTTP protocol ourselves on top of it. That's exactly what nox7 did, a user who shared a small proof of concept on Reddit to show how to send an HTTP GET request using fiber and sockets. Do you really want to do this in your application code?
For me at least, the answer is "no". That's exactly what the RFC warns about; I'm not offended. Instead, we encourage using one of the existing asynchronous frameworks: Amp or ReactPHP.
For example, using ReactPHP, we can write like this:
$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 等框架集成?
The above is the detailed content of PHP8.1 new features explained: Fibers with a grain of salt. For more information, please follow other related articles on the PHP Chinese website!