Hello everyone,
In the TrueAsync RFC 4 thread, John Bafford raised a question about
parallelism.
I would like to share my thoughts and highlight this branch of the discussion.
What is parallelism in the context of coroutines?
Parallelism for coroutines means the ability to execute a coroutine in
one thread or another (but not simultaneously).
In this case, the Scheduler not only manages the execution order of
coroutines but also decides which thread from the thread pool should
be assigned to a coroutine.
What is the problem?
If two different coroutines run in separate threads and write to the
same memory region — that is, to the same PHP object — it will lead to
unpredictable consequences.
The issue is that PHP does not control memory access in such cases and
effectively allows the programmer to shoot themselves in the head.
How can this be solved?
Object transfer policy
The object transfer policy defines how a PHP object can be safely
passed to another coroutine.
Possible transfer methods:
- Via parameters
- Via context
- Via channels
All these methods can be viewed as variations of passing objects
through channels (similar to the Erlang model — no direct sharing).
The same policy applies to all methods.
An interface is defined to guarantee an object’s “thread safety.” For
example, if a coroutine receives an object parameter without this
interface, an error occurs.
In PHP, there are several possible ways to achieve thread safety:
-
Ownership transfer, as in C++/Rust — the object leaves the
current scope and becomes owned by the coroutine. -
Proxy-based access, using a special constructor that creates a
proxy object for access to the real one (similar to actors in Swift). - Shared access with a built-in mutex.
This approach requires minimal changes to the language syntax — in
fact, none at all.
From a performance standpoint, it is perfectly acceptable for PHP to
validate function parameters, so no significant overhead should be
expected.
The main challenge of parallelism lies in making PHP’s internal state,
garbage collector, and memory manager thread-safe.
How does this relate to TrueAsync?
At the moment, TrueAsync does not perform additional checks when
passing parameters to coroutines.
This is a problem — because once PHP introduces concurrency,
developers will start freely using references (&reference) and shared
objects.
When multitasking is later added to coroutines, it will break existing
PHP code that has already been written.
Therefore, if PHP truly aims to become multithreaded, its memory
ownership model must be carefully designed today.
Best Regards, Ed
Hello everyone,
In the TrueAsync RFC 4 thread, John Bafford raised a question about
parallelism.
I would like to share my thoughts and highlight this branch of the discussion.What is parallelism in the context of coroutines?
Parallelism for coroutines means the ability to execute a coroutine in
one thread or another (but not simultaneously).
In this case, the Scheduler not only manages the execution order of
coroutines but also decides which thread from the thread pool should
be assigned to a coroutine.What is the problem?
If two different coroutines run in separate threads and write to the
same memory region — that is, to the same PHP object — it will lead to
unpredictable consequences.The issue is that PHP does not control memory access in such cases and
effectively allows the programmer to shoot themselves in the head.How can this be solved?
Object transfer policy
The object transfer policy defines how a PHP object can be safely
passed to another coroutine.
Possible transfer methods:
- Via parameters
- Via context
- Via channels
All these methods can be viewed as variations of passing objects
through channels (similar to the Erlang model — no direct sharing).The same policy applies to all methods.
An interface is defined to guarantee an object’s “thread safety.” For
example, if a coroutine receives an object parameter without this
interface, an error occurs.In PHP, there are several possible ways to achieve thread safety:
- Ownership transfer, as in C++/Rust — the object leaves the
current scope and becomes owned by the coroutine.- Proxy-based access, using a special constructor that creates a
proxy object for access to the real one (similar to actors in Swift).- Shared access with a built-in mutex.
This approach requires minimal changes to the language syntax — in
fact, none at all.
From a performance standpoint, it is perfectly acceptable for PHP to
validate function parameters, so no significant overhead should be
expected.The main challenge of parallelism lies in making PHP’s internal state,
garbage collector, and memory manager thread-safe.How does this relate to TrueAsync?
At the moment, TrueAsync does not perform additional checks when
passing parameters to coroutines.
This is a problem — because once PHP introduces concurrency,
developers will start freely using references (&reference) and shared
objects.When multitasking is later added to coroutines, it will break existing
PHP code that has already been written.Therefore, if PHP truly aims to become multithreaded, its memory
ownership model must be carefully designed today.
Best Regards, Ed
I’m not sure this is the place to discuss it, nor the time. But C# is cooperative multitasking on top of a VM which is preemptive multitasking. This basically allows you to run multithreaded without worrying about “shooting yourself in the foot” by accessing the same memory, most of the time. In other words, there is plenty of prior art out there and ways to solve this problem. It doesn’t mean we need to solve it today. Trying to solve a problem that doesn’t currently exist and “might” be a problem later is exactly how you end up with overengineered solutions that never actually solve the problem.
— Rob
But it's not a parallelism.
пт, 24 окт. 2025 г., 09:43 Rob Landers rob@bottled.codes:
Hello everyone,
In the TrueAsync RFC 4 thread, John Bafford raised a question about
parallelism.
I would like to share my thoughts and highlight this branch of the
discussion.What is parallelism in the context of coroutines?
Parallelism for coroutines means the ability to execute a coroutine in
one thread or another (but not simultaneously).
In this case, the Scheduler not only manages the execution order of
coroutines but also decides which thread from the thread pool should
be assigned to a coroutine.What is the problem?
If two different coroutines run in separate threads and write to the
same memory region — that is, to the same PHP object — it will lead to
unpredictable consequences.The issue is that PHP does not control memory access in such cases and
effectively allows the programmer to shoot themselves in the head.How can this be solved?
Object transfer policy
The object transfer policy defines how a PHP object can be safely
passed to another coroutine.
Possible transfer methods:
- Via parameters
- Via context
- Via channels
All these methods can be viewed as variations of passing objects
through channels (similar to the Erlang model — no direct sharing).The same policy applies to all methods.
An interface is defined to guarantee an object’s “thread safety.” For
example, if a coroutine receives an object parameter without this
interface, an error occurs.In PHP, there are several possible ways to achieve thread safety:
- Ownership transfer, as in C++/Rust — the object leaves the
current scope and becomes owned by the coroutine.- Proxy-based access, using a special constructor that creates a
proxy object for access to the real one (similar to actors in Swift).- Shared access with a built-in mutex.
This approach requires minimal changes to the language syntax — in
fact, none at all.
From a performance standpoint, it is perfectly acceptable for PHP to
validate function parameters, so no significant overhead should be
expected.The main challenge of parallelism lies in making PHP’s internal state,
garbage collector, and memory manager thread-safe.How does this relate to TrueAsync?
At the moment, TrueAsync does not perform additional checks when
passing parameters to coroutines.
This is a problem — because once PHP introduces concurrency,
developers will start freely using references (&reference) and shared
objects.When multitasking is later added to coroutines, it will break existing
PHP code that has already been written.Therefore, if PHP truly aims to become multithreaded, its memory
ownership model must be carefully designed today.
Best Regards, Ed
I’m not sure this is the place to discuss it, nor the time. But C# is
cooperative multitasking on top of a VM which is preemptive multitasking.
This basically allows you to run multithreaded without worrying about
“shooting yourself in the foot” by accessing the same memory, most of the
time. In other words, there is plenty of prior art out there and ways to
solve this problem. It doesn’t mean we need to solve it today. Trying to
solve a problem that doesn’t currently exist and “might” be a problem later
is exactly how you end up with overengineered solutions that never actually
solve the problem.— Rob
But it's not a parallelism.
пт, 24 окт. 2025 г., 09:43 Rob Landers rob@bottled.codes:
__
Hello everyone,
In the TrueAsync RFC 4 thread, John Bafford raised a question about
parallelism.
I would like to share my thoughts and highlight this branch of the discussion.What is parallelism in the context of coroutines?
Parallelism for coroutines means the ability to execute a coroutine in
one thread or another (but not simultaneously).
In this case, the Scheduler not only manages the execution order of
coroutines but also decides which thread from the thread pool should
be assigned to a coroutine.What is the problem?
If two different coroutines run in separate threads and write to the
same memory region — that is, to the same PHP object — it will lead to
unpredictable consequences.The issue is that PHP does not control memory access in such cases and
effectively allows the programmer to shoot themselves in the head.How can this be solved?
Object transfer policy
The object transfer policy defines how a PHP object can be safely
passed to another coroutine.
Possible transfer methods:
- Via parameters
- Via context
- Via channels
All these methods can be viewed as variations of passing objects
through channels (similar to the Erlang model — no direct sharing).The same policy applies to all methods.
An interface is defined to guarantee an object’s “thread safety.” For
example, if a coroutine receives an object parameter without this
interface, an error occurs.In PHP, there are several possible ways to achieve thread safety:
- Ownership transfer, as in C++/Rust — the object leaves the
current scope and becomes owned by the coroutine.- Proxy-based access, using a special constructor that creates a
proxy object for access to the real one (similar to actors in Swift).- Shared access with a built-in mutex.
This approach requires minimal changes to the language syntax — in
fact, none at all.
From a performance standpoint, it is perfectly acceptable for PHP to
validate function parameters, so no significant overhead should be
expected.The main challenge of parallelism lies in making PHP’s internal state,
garbage collector, and memory manager thread-safe.How does this relate to TrueAsync?
At the moment, TrueAsync does not perform additional checks when
passing parameters to coroutines.
This is a problem — because once PHP introduces concurrency,
developers will start freely using references (&reference) and shared
objects.When multitasking is later added to coroutines, it will break existing
PHP code that has already been written.Therefore, if PHP truly aims to become multithreaded, its memory
ownership model must be carefully designed today.
Best Regards, Ed
I’m not sure this is the place to discuss it, nor the time. But C# is cooperative multitasking on top of a VM which is preemptive multitasking. This basically allows you to run multithreaded without worrying about “shooting yourself in the foot” by accessing the same memory, most of the time. In other words, there is plenty of prior art out there and ways to solve this problem. It doesn’t mean we need to solve it today. Trying to solve a problem that doesn’t currently exist and “might” be a problem later is exactly how you end up with overengineered solutions that never actually solve the problem.
— Rob
You’re technically right — what you described isn’t parallelism, and it mixes a few distinct concerns: memory safety, ownership, and object transfer, all under the label of “parallelism.” But coroutines are explicitly cooperative. They don’t run in parallel unless a scheduler explicitly assigns them to threads, and we’re a long way from the VM being capable of that.
I’m also not sure why we’d even need an “object transfer” system. The entire point of threads is that memory is shared. If you want to pass an object to another thread, you just give it a pointer — full stop. The reason thread-safe extensions need to jump through hoops is TSRM: each thread gets its own VM context and thread-local memory. That’s an engine-level design choice, not a missing userland feature. Opcache, for instance, could theoretically use global memory with traditional locks instead of file locks in ZTS mode, but that’s deep in engine territory — far from anything TrueAsync needs to consider right now.
So practically speaking, it’s not worth designing around this yet. The engine would need massive adaptation before userland could safely talk about “parallelism.”
What you’re actually raising sounds more like concurrency — specifically, managing mutable state across concurrent coroutines. That’s a valid topic, but concurrency control (locks, ownership semantics, etc.) doesn’t belong in TrueAsync itself. If anything, that would come later as a separate layer or RFC once the concurrency model stabilizes. It really should just be listed as Future Scope on that RFC and dealt with if or when the RFC lands.
— Rob
So practically speaking, it’s not worth designing around this yet. The engine would need massive adaptation before userland could safely talk about “parallelism.”
I agree. However, this question was raised. Perhaps there’s a larger
team of developers working on a new virtual machine for PHP? I don’t
know anything about that. But if that’s indeed happening, then the
topic becomes relevant.
As for me personally, I don’t see any practical benefit in introducing
multitasking to PHP. It would require significant development effort
while offering very little economic value in typical PHP use cases.
Still, it’s possible that someone plans to build a PHP-Native version
for a wider range of operating systems — and in that case, such a
feature might indeed be needed.
--- Ed
So practically speaking, it’s not worth designing around this yet. The engine would need massive adaptation before userland could safely talk about “parallelism.”
I agree. However, this question was raised. Perhaps there’s a larger
team of developers working on a new virtual machine for PHP? I don’t
know anything about that. But if that’s indeed happening, then the
topic becomes relevant.As for me personally, I don’t see any practical benefit in introducing
multitasking to PHP. It would require significant development effort
while offering very little economic value in typical PHP use cases.
Still, it’s possible that someone plans to build a PHP-Native version
for a wider range of operating systems — and in that case, such a
feature might indeed be needed.--- Ed
The only thing that is relevant to this discussion (that I know of), is my refactoring of TSRM so that FrankenPHP doesn't need to maintain it's own thread pool of PHP workers. It's only relevant because it takes away the thread-local bits and makes it possible – not that you'd ever want to do it, unless you like segfaults – to run the engine concurrently across multiple threads. With a decent preemptive scheduler (this is distinct from the userland/TrueAsync scheduler), you could pack multiple requests in the same thread while waiting on I/O, and have a different thread pick up work if the I/O finished too early. This will be entirely transparent to userland and other than TSRM changes and a few convienent hooks, be handled completely by a FrankenPHP (or even, Swoole) scheduler.
Where this intersects with TrueAsync is being able to further pack coroutines (and especially "native" coroutines like file_get_contents(), PDO, etc) across fewer threads, making full use of CPUs. There is no need for parallelism in this model – at least when it comes to it being visible to userland. And this is just pie-in-the-sky thinking, because first, TrueAsync needs to be worked on. It would be more beneficial to everyone, to focus on that, and not this. At least right now, it is a waste of everyone's time.
That's my roadmap for FrankenPHP over the coming years and they're almost completely unrelated to coroutines and TrueAsync.
— Rob
It seems I understand what this is about. You want the VM to be
transferable between threads.
Okay, then I have no further questions.
Thank you, Ed