Re: PHP True Async RFC Stage 4
| From: | John Bafford | Date: | Wed, 22 Oct 2025 22:56:09 +0000 |
| Subject: | Re: PHP True Async RFC Stage 4 | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-128914@lists.php.net to get a copy of this message | ||
Hi Edmond,
> On Oct 22, 2025, at 15:43, Edmond Dantes <edmond.ht@gmail.com> wrote:
>
> Hi
>
>> * Is TrueAsync intended strictly to enable concurrency without parallelism (e.g.
>> single-threaded cooperative multitasking)?
>> Is there a future path in mind for parallelism (actual simultaneous execution)?
>
> In short, it mostly depends on the PHP core. TrueAsync itself could
> support multithreading.
> At the moment, achieving a fully multithreaded PHP seems extremely
> complex and offers very little benefit.
> In other words, the cost-to-benefit ratio is close to “irrational.”
>
> If you’d like, I can elaborate on this idea, though probably not in this thread.
To be clear, since I didn't explicitly state this, my point is that I would like to see
whatever gets introduced by any RFC (as this one is) that is likely to be used as a stepping stone
to full multithreaded async PHP (whether or not we think that such a destination is likely on any
practical timescale) _NOT_ get in the way of that destination. That is, I don't want us to go
partway down a path, only to find later that we can't make it to the destination because of a
bad or incomplete decision early on. Which is why I'm asking about stuff that might not be in
scope for this RFC, because it _will_ be in-scope for some future RFC, and if we wind up with a bad
interface now, it makes that future RFC's job unnecessary harder. And since this isn't
going to be shipping to any end-user for at least another year, we have _plenty_ of time to make
sure we get the interface right.
>> * Rob Landers brought up the question about multiple-value Awaitables.
>> I agree with him that it is a potential footgun. If an Awaitable is going to return
>> multiple values, then it should implement have a different interface to indicate that contract.
>
> It seems to me that this discussion has gotten a bit tangled:
>
> 1. Functions like awaitXX are not part of this RFC, yet we’re
> discussing them. Is that really necessary?
I can't find where this
awaitXX function is defined, so I can't comment on
that. But I didn't bring it up, so I'm unclear why you are.
> 2. Awaitable objects do not return multiple values.
So you say "Awaitable objects do not return multiple values." but the description of the
Awaitable interface says it allows for that. Unless I'm misunderstanding something, I
don't think that makes any sense. And also you seem to be saying that some objects are
Awaitable, and also there's an Awaitable interface that means something different, which is
definitely going to cause confusion.
> 3. The Awaitable interface is basic for others, just like in many
> other programming languages. And for some reason, it’s not considered
> a problem there.
> So far, no real example has been found where this would actually be a problem.
This may not be your intention, but to me it feels like you're just dismissing Rob and my
concern, which is that single-value and multiple-value are two completely different beasts and PHP
shouldn't allow you to just casually mix them without throwing a compile-time error. Rob has
provided an example where this _is_ a problem.
And Swift does recognize this as a problem, that's why if you want to iterate on the result of
an asynchronous stream of values, you use an AsyncStream, and not a Task/Coroutine. (Granted: the
stream's values might be sourced from within a Task, but that's an implementation detail.
And why there's also a TaskGroup if what you want is to spawn a one async task per item in an
iterable and iterate over the results as they complete.)
(btw, if you haven't read through the Swift Evolution proposals for structured concurrency, I
highly recommend you do, if only to see what/how Swift has chosen to do. And then what they got
wrong and the hoops they jumped through to try and remedy it afterwards, some of which many people
here would find quite distasteful.)
>> For cancellation, I'm confused on the resulting value.
> Thank you, that’s a great catch!!!
> I need to check this case.
>
>> For clarity, the case when exit/die is called outside of async code
> In TrueAsync, there is no longer any non-asynchronous code. Everything
> is a coroutine.
> Actually, that’s not entirely accurate, but it’s fine to think of it that way.
Then, just saying, this is a place where people are going to be confused, and it needs to be stated
clearly. The description in "exit and die keywords" section shouldn't be under
cancellation policy, and shouldn't special-case being called within a coroutine. If exit/die
still immediately terminate execution, then there should be no confusion about that.
>> I think Async\protect() and forcibly cancelling coroutines beyond calling
>> $coroutine->cancel() should be removed.
>
> If PHP were a language for spacecraft or airplanes, where extremely
> high reliability is required, this might make sense.
> However, the current model allows for more concise code and has
> already proven itself well in other languages.
There may be a misunderstanding here. I'm not saying you should remove cooperative cancelation.
That's perfectly fine and should stay. With cooperative cancellation, it's not necessary
to assert you're in a critical section, you just ignore the cancellation signal and keep on
processing. What I'm proposing that specifically Async\protect() and *forcibly* cancelling
coroutines should be removed. (You'll note that in some multithreading APIs, forcibly
terminating threads, while allowed, is very much discouraged because that can leave things in
inconsistent states that causes future crashes or unpredictable behavior.)
> I actually have a stricter explanation for why the cancellable model
> is more advantageous than any other.
> This particular model fits well for read operations, which are usually
> as frequent as, or even more frequent than, write operations.
> Therefore, this approach simplifies asynchronous code while keeping
> the overall risk low.
The RFC should include a description of _why_ cooperative cancellation has been chosen.
> Thanks, Ed
-John