PHP and parallelism

php.internals

Edmond Dantes

312 days ago
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: 1. Via parameters 2. Via context 3. 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: 1. **Ownership transfer**, as in C++/Rust — the object leaves the current scope and becomes owned by the coroutine. 2. **Proxy-based access**, using a special constructor that creates a proxy object for access to the real one (similar to actors in Swift). 3. **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

Rob Landers

312 days ago
On Fri, Oct 24, 2025, at 08:34, Edmond Dantes wrote:
> 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: > 1. Via parameters > 2. Via context > 3. 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: > 1. **Ownership transfer**, as in C++/Rust — the object leaves the > current scope and becomes owned by the coroutine. > 2. **Proxy-based access**, using a special constructor that creates a > proxy object for access to the real one (similar to actors in Swift). > 3. **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

Edmond Dantes

312 days ago
But it's not a parallelism. пт, 24 окт. 2025 г., 09:43 Rob Landers <rob@bottled.codes>:

Rob Landers

312 days ago
On Fri, Oct 24, 2025, at 09:30, Edmond Dantes wrote:
> But it's not a parallelism. > > пт, 24 окт. 2025 г., 09:43 Rob Landers <rob@bottled.codes>: >> __ >> >> >> On Fri, Oct 24, 2025, at 08:34, Edmond Dantes wrote: >>> 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: >>> 1. Via parameters >>> 2. Via context >>> 3. 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: >>> 1. **Ownership transfer**, as in C++/Rust — the object leaves the >>> current scope and becomes owned by the coroutine. >>> 2. **Proxy-based access**, using a special constructor that creates a >>> proxy object for access to the real one (similar to actors in Swift). >>> 3. **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

Edmond Dantes

312 days ago
> > 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

Rob Landers

312 days ago
On Fri, Oct 24, 2025, at 11:43, Edmond Dantes wrote:
> > > > 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

Edmond Dantes

312 days ago
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