I’m way behind on this trend, or non-trend as the case may be. I’m catching up, and these are notes for July 2024.
History
Go and NodeJS proved how to scale up network servers using single-threaded, cooperative multitasking servers. The PHP community responded by creating libraries to allow the creation of similar servers in PHP, using php-cli. These libraries competed and used a lot of tricks. The PHP language responded by adding Fibers in PHP 8.1. Because these developments occurred in parallel, different libraries use different underlying technologies, resulting in a few different server stacks and a fragmented framework universe. Also, during this time, PHP progressed from version 5 to 8.3.
Traditional web-server-based PHP programming (FCGI and Apache mod_php) is stateless, and each script execution is like running the program anew; each execution ends with output, or an error. These async platforms are stateful, and once the process is spawned, it keeps running to process new requests, and produce output, but the process doesn’t normally terminate, even on some errors.
Callbacks, Coroutines, Fibers, Threads, Processes
In the 2000s, the favored way to run PHP apps was to run within an Apache process. To scale up and deal with blocking IO, the server ran multiple server processes using the native processes.
If the OS supported threads, like Windows does, it might use threads instead. Threads are like lightweight processes that run within a process’ memory. Apache2 added thread support, but PHP threads don’t work with it. PHP has a pthreads library, and a newer parallel library to implement threads, but these run in PHP-CLI, not with the the mod_php or even the FCGI server.
NodeJS created an async library that worked with JavaScript’s callbacks. JS added promises, which was a feature to sequence callbacks, using a more readable syntax.
Go brought back the old idea of coroutines, which are functions that can yield execution, and then resume execution. (This is similar to generators.) The Swoole Coroutine extension implemented coroutines, and they built the Swoole Library on top of that.
PHP RFC Fibers is filling a gap between threads and coroutines. As noted, PHP doesn’t do threads. Coroutines are functions that yield execution, but don’t have a call stack. Threads have a call stack, but implementations like Java’s are based on classes. Fibers are functions that yield (like coroutines), but also have a call stack, like Threads.
The problem with using async callbacks or promises, is that all the function calls must be async or return Promises. What Fibers allow is for fiber code to call traditional synchronous code – you can mix calls to async and traditional libraries.
With the addition of Fibers, the async library landscape changed.
Library History
In PHP5, the main async feature was streams, and secondarily the Socket, PCNTL, and pthreads extensions. Streams allow you to break up IO into chunks.
The async libraries like ReactPHP and AMPHP chunked the streams into events, and processed them with an event loop. In the event loop, callback functions are sent chunks of data for processing. Each function does some work on the data, and then returns control back to the event loop.
Popular libraries for MySQL, Redis, and other services, were not async; this meant that making calls to them within an event loop would get “stuck” waiting for a response from the service.
So, an async library needed to be written for each of these services. ReactPHP did this in PHP code in 2012. They also created a PHP Promises library, to write callback code.
AMPHP started in 2018, back in the PHP5 days, and were also libraries for async services.
Swoole added the coroutine feature, and wrote async libraries using coroutines, however, unlike ReactPHP, the libraries were written in C++, and included in the extension. Swoole was, and is super-fast.
In 2021, a conflict over security caused some developers to fork Swoole and create OpenSwoole. I’m not sure of the status of these two, but it looks like Swoole is doing better, and OpenSwoole might be moribund. Search for Swoole on PECL and look at the release dates. Swoole is popular mainly in China.
2021 also introduced Fibers in PHP8.1. Created by Aaron Piotrowski of AMPHP, it allowed for cleaner code in the async libraries, and made the libraries more compatible with synchronous libraries.
With Fibers, the old async libraries are being rewritten to use Fibers. It brought together the AMP and React communities to produce the Revolt event loop.
The Revolt event loop doesn’t have Swoole’s speed or scalability, but it can drastically improve it with one of the PHP event loop extension, and the extension that integrates libuv is written by AMP devs.
For high performance, at this time, I think it’s easier to deploy Swoole than AMP + uv.
Opinions
Many programmers want to speed up Laravel and Symfony apps using async libraries. There was even a WordPress Swoole effort.
This seems like a dead end to me.
I think that these event-loop libraries are probably better suited for writing fresh code for things like chat servers, game servers, whiteboard servers, and other servers that require extremely fast responses, maintain state in memory (or in Redis), and handle many socket connections.
That’s my 2 cents about this.