Hi,

I've been lurking around in the discussion for a while, and I'd like to chime 
in now since the main, glaring issue with this proposal has only been 
explicitly mentioned by Rowan Tomminis, with that subthread quickly 
degenerating with misguided replies.

PHP as a language absolutely needs a persistent worker mode like in all other 
backend languages, which will greatly improve performance by avoiding all 
overhead related to request initialization.

However, the current proposal of adding support for worker mode SAPIs based on 
the usual PHP superglobals is fundamentally incompatible with concurrency (aka 
async, aka swoole, amphp, fiber-based concurrent runtimes in general), and I 
believe would steer the PHP ecosystem in the wrong direction.

Rowan already offered a nice example of why earlier in the thread, but as an 
explanation to those that may not have understood that, so I whipped up a 
briefer at https://gist.github.com/danog/f0e9103e6a7e1bcec1b92c411a3c4607



So no, unlike what I've read in another message here, "The nodejs curse [...] 
where async and co may actually slow down your whole node." is simply false for 
the majority of modern usecases, because the majority of modern applications is 
I/O-intensive, not CPU-intensive.


Implementing a worker API the way it is proposed is fundamentally incompatible 
with userland cooperative schedulers aka event loops like amphp or reactphp, 
and each request would be handled, just like in php-fpm, in a separate OS 
thread, not in a much more efficient userland thread.

Cooperative schedulers implemented outside of PHP in the form of an extension 
such as swoole would also not be able to easily make use of the initially 
proposed API to handle requests in separate coroutines, even if the 
handle_request function was intercepted by swoole to return control to the 
swoole event loop (which would already make it superfluous as a PHP API), since 
the proposal involves messing around with the usual superglobals, which as 
mentioned by Rowan would require manual copying of the superglobals before 
using them in a newly spawned swoole coroutine.

I believe that a much, much better way of implementing a worker mode in PHP 
core would be to provide a fiber-aware function/static method returning, upon 
receiving a request, a class implementing the PSR-7 RequestInterface.

Fiber-aware here means that the function should behave in a way similar to how 
all native PHP I/O functions should behave in an upcoming Native Event Loop RFC 
I'm planning to make.

The idea here is to make all I/O related functions, including this new 
wait_request function, completely async in a manner that is compatible with 
fibers and pure PHP event loops like amphp.

It would essentially work as follows: an event loop like uv is integrated 
within PHP itself at least for the native stream wrapper (I.e. all filesystem 
and network functions, file_get_contents and so on).
Extensions will be provided an API to interact with the event loop.

I'm currently finalizing the details, and might probably make a first RFC in 
the coming weeks, suffice to say that everything will work in a manner very 
similar to how async works in both the ext-pq and php-tokio extensions, albeit 
with fiber integration: a separate event loop (let's call it native) is started 
in another OS thread (like with ext-pq or php-tokio, WITHOUT the need for ZTS, 
as no PHP data structures are modified in the native event loop), events are 
sent via a single descriptor from the native event loop to the userland event 
loop (I.e. amphp).

If running inside a fiber, tasks are queued to the native event loop and the 
fiber is suspended with a NativeSuspension, then resumed by the userland event 
loop.

If not running inside a fiber, tasks are queued to the native event loop and 
control is returned to the userland event loop.

Essentially, my proposal is almost exactly what is already being done in 
https://github.com/danog/php-tokio, but library-agonstic and implemented inside 
of PHP itself, perhaps even using Rust and tokio as well.

I feel that the current direction of the discussion of PHP worker modes is 
wrong, as it is mostly ignoring the presence of a perfectly usable concurrency 
API in PHP (fibers): this has potential to cause a big split in the PHP 
ecosystem, unless PHP finally fully embraces concurrency and async with a 
native event loop proposal, like the one I intend to present soon.

I hope that further discussion of a worker mode continues with an eye to the 
future with native concurrency :)

Regards,
Daniil Gentili.

P. S. Just in case to avoid confusion for some, frankenphp does NOT add native 
concurrency to php using goroutines, as control to the go event loop is only 
returned when calling functions like header or echo which cause a suspension of 
the goroutine because an I/O operation is made on the go side, but

1) That's incompatible with fibers, and not just because of the minor go 
compatibility bug which is being fixed, but because the go event loop is not 
integrated with any php event loop, and thus does not know to return control to 
any eventual php fiber when needed, and will just block all PHP fibers until 
that single go I/O operation is done (unlike in php-tokio, where the rust tokio 
event loop is fully integrated with the php event loop (currently just revolt)).

2) It doesn't even replace the native stream wrapper with go-backed async I/O 
like swoole does (though both this and php event loop integration like in 
php-tokio is fully possible in frankenphp with a bit of work, I could actually 
lend a hand if needed...)

Reply via email to