Re: PHP True Async RFC

From: Date: Sat, 08 Mar 2025 08:13:14 +0000
Subject: Re: PHP True Async RFC
References: 1 2 3 4 5 6 7 8 9 10 11 12 13  Groups: php.internals 
Request: Send a blank email to internals+get-126634@lists.php.net to get a copy of this message
On Sat, Mar 8, 2025, at 09:06, Eugene Sidelnyk wrote: >> > >> The uncoloring of functions in PHP is probably one of the most annoying aspects of fibers, >> IMHO. It's hard to explain unless you've been using them awhile. But, with colored >> functions, the caller has control over when the result is waiting on -- it could be now, it could be >> in a totally different part of the program, or not at all. With fibers, the author of the function >> you are calling has control over when the result is waited on (and they don't have control over >> anything they call). This can create unpredictable issues when writing code where a specific part >> wrote some code thinking it had exclusive access to a property/variable. However, someone else >> changed one of the functions being called into an async function, making that assumption no longer >> true. >> >> With colored functions, the person making changes also has to update all the places where >> it is called and can validate any assumptions are still going to be true; uncolored functions means >> they almost never do this. This results in more work for people implementing async, but more correct >> programs overall. >> >> But back to the awaiting on results. Say I want to read 10 files: >> >> for ($i = 0; $i < 10; $i++) $results[] = file_get_contents($file[$i]); >> >> Right now, we have to read each file, one at a time, because this is synchronous. Even with >> this RFC and being in a fiber, the overall execution might be non-blocking, but the code still reads >> one file after another sequentially. Fibers do not change this. >> >> With this RFC (in its original form), we will be able to change it so that we can run it >> asynchronously though and choose when to wait: >> >> for($i = 0; $i < 10; $i++) $results[] = async\async(fn($f) => file_get_contents($f), >> $file[$i]); >> // convert $results into futures somehow -- though actually doesn't look like it is >> possible. >> $results = async\awaitAll($results); >> >> In that example, we are deliberately starting to read all 10 files at the same time. If we >> had colored functions (aka, async/await) then changing file_get_contents to async would mean you >> have to change everywhere it is called too. That means I would see that file_get_contents is >> synchronous and be able to optimize it without having to even understand the reasoning (in most >> cases). I was a user of C# when this happened to C#, and it was a pain... So, at least with PHP >> fibers, this won't be AS painful, but you still have to do some work to take full advantage of >> them. >> >> I kind of like the idea of a nursery for async, as we could then update >> file_get_content's return type to something like string|false|future<string|false>. In >> non-async, you have everything behave as normal, but inside a nursery, it returns a future that can >> be awaited however you want and is fully non-blocking. In other words, simply returning a future is >> enough for the engine to realize it should spawn a fiber (similar to how using yield works with >> generators). >> >> In any case, I believe that a nursery requires the use of colored functions. That may be >> good or bad, but IMHO makes it much more useful and easier to write correct and fast code. >> > > > In my opinion, colored functions is the worst thing that could happen to PHP. > > https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function† > !¤·‚Ã’r–”{Y > Describes quite expressively what's wrong about this approach. > > As the result, you will make everything async. > Want a repository? It will be all async. > Want a logger? Also async. > Need to cache something? Make it async. > > This is going to be a ton of changes, when currently sync (blue function) will have to become > async (red one). > > The way amphp goes - it's the right way. They have had this problem of red-blue functions > a long ago until Fibers came into place. > > What they used until third version is generator-based coroutines, so that instead of returning > actual object, you spoil the signature of the function and return generator that will return that > object (iow, "Promise"). > > This is just annoying, and IMO should not be considered. My point in the email is that this happens anyway. With colored functions, you /*always/* decide how to handle async. Which, as you mentioned, can be annoying. With uncolored functions, you */never/* get to decide unless you wrap it in a specific form (async\run or async\async, in this RFC), which ironically colors the function. I can't think of any way around it. My biggest issue with this RFC is that it results in **multiple** colors: FiberHandle, Future, and Resume. — Rob

« previous php.internals (#126634) next »