Hello everyone!
I would like to introduce an RFC for adding full-stack fibers to PHP: https://wiki.php.net/rfc/fibers
Fibers are primarily used to implement green-threads or coroutines for asynchronous I/O. Fibers are similar to threads, except fibers exist within a single thread and require cooperative scheduling of the fibers by the process. Since fibers do not require a full CPU context switch, they are lightweight and more performant than multi-processing or threading for awaiting I/O.
An implementation as an extension is at https://github.com/amphp/ext-fiber
Fibers are a complex feature. The RFC contains many examples and links to code using fibers to help explain and demonstrate what is possible, however I’m certain many more questions and concerns will arise. Looking forward to feedback and discussion.
Aaron Piotrowski
Hi Aaron, this is very interesting to me. Can I ask why this approach as
opposed to other paradigms like promises, coroutines, etc? You mentioned
async/await in the future scope, and I assume most of these patterns can be
implemented once there is an underlying functionality. Basically, why
fibers instead of x?
You also mentioned this isn't really intended to be used directly, but with
a library such as AMPHP. IS the expectation that non-blocking I/O
functionality like database drivers and file operation be provided by
libraries as well?
I hope I don't come off as critical, I am merely curious. Thank you for
pushing this forward, as async is something PHP has been lacking and should
have IMO to compare favourably to other alternatives that do.
Regards, Peter.
Hello everyone!
I would like to introduce an RFC for adding full-stack fibers to PHP:
https://wiki.php.net/rfc/fibersFibers are primarily used to implement green-threads or coroutines for
asynchronous I/O. Fibers are similar to threads, except fibers exist within
a single thread and require cooperative scheduling of the fibers by the
process. Since fibers do not require a full CPU context switch, they are
lightweight and more performant than multi-processing or threading for
awaiting I/O.An implementation as an extension is at https://github.com/amphp/ext-fiber
Fibers are a complex feature. The RFC contains many examples and links to
code using fibers to help explain and demonstrate what is possible, however
I’m certain many more questions and concerns will arise. Looking forward to
feedback and discussion.Aaron Piotrowski
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Peter,
Hi Aaron, this is very interesting to me. Can I ask why this approach as
opposed to other paradigms like promises, coroutines, etc? You mentioned
async/await in the future scope, and I assume most of these patterns can be
implemented once there is an underlying functionality. Basically, why
fibers instead of x?
Promises result in the “What color is your function” problem as described in the introduction of the RFC. Returning promises from functions means that functions calling those functions must also return promises, resulting in the entire call stack needing to return promises.
Fibers are a method of implementing coroutines or interruptible functions. Promises likely would still be used as placeholders in libraries using fibers, but coroutines written using fibers do not have to return another placeholder. Fibers allow async code to be indistinguishable from sync code, as opposed to an approach where async functions must return a promise.
You also mentioned this isn't really intended to be used directly, but with
a library such as AMPHP. IS the expectation that non-blocking I/O
functionality like database drivers and file operation be provided by
libraries as well?
Since most code written for PHP is blocking, yes, such libraries/frameworks would need to provide functionality such as database drivers. Both AMPHP and ReactPHP already have existing async drivers available for several different popular database systems. AMPHP’s postgres, mysql, and redis drivers already have a version using fibers.
I hope I don't come off as critical, I am merely curious. Thank you for
pushing this forward, as async is something PHP has been lacking and should
have IMO to compare favourably to other alternatives that do.
You didn’t com off as critical at all! These were good questions to ask. I too think if PHP is to add support for async code it should compare favorably to other languages. I think fibers offer a distinct advantage to using promise for async code.
Cheers,
Aaron Piotrowski
Hello Aaron,
First, I want to say that I love this proposal and would love to see it land in the next PHP release, but I have one question regarding this:
Promises result in the “What color is your function” problem as described in the introduction of the RFC. Returning promises from functions means that functions calling those functions must also return promises, resulting in the entire call stack needing to return promises.
Hack-Lang provides HH\Asio\join
function which allows awaiting Awaitables in sync code, so you are capable of running multiple async tasks concurrently without having to declare the entire call stack as "async" or with an "Awaitable" return type, isn't this possible?
use namespace HH\Asio;
async function async_task(): Awaitable<void> {
await Asio\usleep(1000000);
}
<<__EntryPoint>>
function main(): void {
$start = microtime(true);
$async = async {
concurrent {
await async_task();
await async_task();
};
return 'hello';
};
$result = Asio\join($async);
printf('Result: %s ( %f )', $result, microtime(true) - $start); // output "Result: hello ( 1.010382 )"
}
Regards,
Saif.
‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
Hi Peter,
Hi Aaron, this is very interesting to me. Can I ask why this approach as
opposed to other paradigms like promises, coroutines, etc? You mentioned
async/await in the future scope, and I assume most of these patterns can be
implemented once there is an underlying functionality. Basically, why
fibers instead of x?Promises result in the “What color is your function” problem as described in the introduction of the RFC. Returning promises from functions means that functions calling those functions must also return promises, resulting in the entire call stack needing to return promises.
Fibers are a method of implementing coroutines or interruptible functions. Promises likely would still be used as placeholders in libraries using fibers, but coroutines written using fibers do not have to return another placeholder. Fibers allow async code to be indistinguishable from sync code, as opposed to an approach where async functions must return a promise.
You also mentioned this isn't really intended to be used directly, but with
a library such as AMPHP. IS the expectation that non-blocking I/O
functionality like database drivers and file operation be provided by
libraries as well?Since most code written for PHP is blocking, yes, such libraries/frameworks would need to provide functionality such as database drivers. Both AMPHP and ReactPHP already have existing async drivers available for several different popular database systems. AMPHP’s postgres, mysql, and redis drivers already have a version using fibers.
I hope I don't come off as critical, I am merely curious. Thank you for
pushing this forward, as async is something PHP has been lacking and should
have IMO to compare favourably to other alternatives that do.You didn’t com off as critical at all! These were good questions to ask. I too think if PHP is to add support for async code it should compare favorably to other languages. I think fibers offer a distinct advantage to using promise for async code.
Cheers,
Aaron Piotrowski
To unsubscribe, visit: https://www.php.net/unsub.php
Hello Aaron,
First, I want to say that I love this proposal and would love to see it land in the next PHP release, but I have one question regarding this:
Promises result in the “What color is your function” problem as described in the introduction of the RFC. Returning promises from functions means that functions calling those functions must also return promises, resulting in the entire call stack needing to return promises.
Hack-Lang provides
HH\Asio\join
function which allows awaiting Awaitables in sync code, so you are capable of running multiple async tasks concurrently without having to declare the entire call stack as "async" or with an "Awaitable" return type, isn't this possible?use namespace HH\Asio; async function async_task(): Awaitable<void> { await Asio\usleep(1000000); } <<__EntryPoint>> function main(): void { $start = microtime(true); $async = async { concurrent { await async_task(); await async_task(); }; return 'hello'; }; $result = Asio\join($async); printf('Result: %s ( %f )', $result, microtime(true) - $start); // output "Result: hello ( 1.010382 )" }
Regards,
Saif.
Hi Saif,
HH\Asio\join()
implements a synchronous await (I don't know the details of how its implemented, possibly involving entering and exiting the built-in event loop), but it does not solve the problem that functions using await
need to be declared using async
and return an Awaitable. Your example declares async_task()
as async, while a similar function using the proposed fiber API would not need to change the function declaration to use Fiber::suspend()
. There's an example in the RFC using Amp\delay()
that is very similar to your code sample.
Fibers allow existing interfaces to be implemented using either sync or async I/O because the interface does not need to change to return promises/awaitables.
Cheers,
Aaron Piotrowski
Hello everyone!
I would like to introduce an RFC for adding full-stack fibers to PHP: https://wiki.php.net/rfc/fibers
Fibers are primarily used to implement green-threads or coroutines for asynchronous I/O. Fibers are similar to threads, except fibers exist within a single thread and require cooperative scheduling of the fibers by the process. Since fibers do not require a full CPU context switch, they are lightweight and more performant than multi-processing or threading for awaiting I/O.
An implementation as an extension is at https://github.com/amphp/ext-fiber
Fibers are a complex feature. The RFC contains many examples and links to code using fibers to help explain and demonstrate what is possible, however I’m certain many more questions and concerns will arise. Looking forward to feedback and discussion.
This is interesting, and potentially very useful.
I am curious about how you propose access to shared memory across fibers? What will happen if two fibers try to update a $GLOBALS variable at the same time? Or a property of the same object? How will developers manage that?
-Mike
P.S. Have you considered concurrency functionality like in GoLang[1] e.g. channels, where the mantra is "Do not communicate by sharing memory; instead, share memory by communicating?"
Hello everyone!
I would like to introduce an RFC for adding full-stack fibers to PHP: https://wiki.php.net/rfc/fibers
Fibers are primarily used to implement green-threads or coroutines for asynchronous I/O. Fibers are similar to threads, except fibers exist within a single thread and require cooperative scheduling of the fibers by the process. Since fibers do not require a full CPU context switch, they are lightweight and more performant than multi-processing or threading for awaiting I/O.
An implementation as an extension is at https://github.com/amphp/ext-fiber
Fibers are a complex feature. The RFC contains many examples and links to code using fibers to help explain and demonstrate what is possible, however I’m certain many more questions and concerns will arise. Looking forward to feedback and discussion.
This is interesting, and potentially very useful.
I am curious about how you propose access to shared memory across fibers? What will happen if two fibers try to update a $GLOBALS variable at the same time? Or a property of the same object? How will developers manage that?
-Mike
P.S. Have you considered concurrency functionality like in GoLang[1] e.g. channels, where the mantra is "Do not communicate by sharing memory; instead, share memory by communicating?"
[1] https://medium.com/@thejasbabu/concurrency-in-go-e4a61ec96491#:~:text=Do%20not%20communicate%20by%20sharing,race%20conditions%2C%20memory%20management%20etc https://medium.com/@thejasbabu/concurrency-in-go-e4a61ec96491#:~:text=Do%20not%20communicate%20by%20sharing,race%20conditions%2C%20memory%20management%20etc.
Hi Mike,
Fibers do not change the single-threaded nature of PHP. Only a single fiber can be running at one time, so memory cannot be modified simultaneously.
There are synchronization issues when writing asynchronous code using either stackless or stackful coroutines, as anyone who has worked with AMPHP or ReactPHP can tell you. Multiple fibers (coroutines, green-threads, whatever you want to call them) will interleave execution. Multiple interleaved fibers can change object state between pausing and resuming, which I'm guessing is more to what you were concerned about, rather than literal simultaneous modification that can occur with threads. The RFC does not provide tools to synchronize memory access, as these can be implemented in user space. Fibers don't provide the entire API, just the "bare-metal" API needed to implement various styles of concurrency in user space code.
AMPHP provides synchronization tools such as mutexes, semaphores, parcels, and channels in https://github.com/amphp/sync https://github.com/amphp/sync and https://github.com/amphp/parallel https://github.com/amphp/parallel. Other libraries could provide similar tools, though perhaps with a different approach. We too like the Go-style of concurrency and look to emulate it in AMPHP v3.
Cheers,
Aaron Piotrowski
Hello everyone!
I would like to introduce an RFC for adding full-stack fibers to PHP: https://wiki.php.net/rfc/fibers https://wiki.php.net/rfc/fibers
Fibers are primarily used to implement green-threads or coroutines for asynchronous I/O. Fibers are similar to threads, except fibers exist within a single thread and require cooperative scheduling of the fibers by the process. Since fibers do not require a full CPU context switch, they are lightweight and more performant than multi-processing or threading for awaiting I/O.
An implementation as an extension is at https://github.com/amphp/ext-fiber https://github.com/amphp/ext-fiber
Fibers are a complex feature. The RFC contains many examples and links to code using fibers to help explain and demonstrate what is possible, however I’m certain many more questions and concerns will arise. Looking forward to feedback and discussion.
This is interesting, and potentially very useful.
I am curious about how you propose access to shared memory across fibers? What will happen if two fibers try to update a $GLOBALS variable at the same time? Or a property of the same object? How will developers manage that?
-Mike
P.S. Have you considered concurrency functionality like in GoLang[1] e.g. channels, where the mantra is "Do not communicate by sharing memory; instead, share memory by communicating?"
[1] https://medium.com/@thejasbabu/concurrency-in-go-e4a61ec96491#:~:text=Do%20not%20communicate%20by%20sharing,race%20conditions%2C%20memory%20management%20etc <https://medium.com/@thejasbabu/concurrency-in-go-e4a61ec96491#:~:text=Do not communicate by sharing,race conditions, memory management etc>.
Hi Mike,
Thanks for the reply.
Fibers do not change the single-threaded nature of PHP. Only a single fiber can be running at one time, so memory cannot be modified simultaneously. There are synchronization issues when writing asynchronous code using either stackless or stackful coroutines, as anyone who has worked with AMPHP or ReactPHP can tell you. Multiple fibers (coroutines, green-threads, whatever you want to call them) will interleave execution.
So if I am to understand correctly, one fiber could block all others, so fiber code will need to be well-behaved and not block much like how Node code must not block when used as a web server? If I understand correctly, no need to reply about this.
Multiple interleaved fibers can change object state between pausing and resuming, which I'm guessing is more to what you were concerned about, rather than literal simultaneous modification that can occur with threads.
Correct.
The RFC does not provide tools to synchronize memory access, as these can be implemented in user space.
Would it be appropriate of me to ask for a section that discusses how that might be done in user space in the RFC, at least with some simple pseudo-code, or if is it non-trivial than a link to where it is discussed in depth?
Fibers don't provide the entire API, just the "bare-metal" API needed to implement various styles of concurrency in user space code.
AMPHP provides synchronization tools such as mutexes, semaphores, parcels, and channels in https://github.com/amphp/sync https://github.com/amphp/sync and https://github.com/amphp/parallel https://github.com/amphp/parallel. Other libraries could provide similar tools, though perhaps with a different approach. We too like the Go-style of concurrency and look to emulate it in AMPHP v3.
Thanks in advance.
-Mike
Hi Mike,
Would it be appropriate of me to ask for a section that discusses how that might be done in user space in the RFC, at least with some simple pseudo-code, or if is it non-trivial than a link to where it is discussed in depth?
Absolutely! I added a short example implementation of a mutex to the RFC under https://wiki.php.net/rfc/fibers#how_do_various_fibers_access_the_same_memory. The code uses a simple queue of fibers waiting to access the mutex to acquire and release the lock.
A channel might be implemented with a queue of messages where the receiving fiber suspends if the queue is empty. Sending a message on the channel would resume a suspended fiber that was waiting to receive a message.
Hopefully that helps. If something is still unclear or an additional example would help, don't hesitate to ask.
Cheers!
Aaron Piotrowski
Hi Mike Schinkel,
This is interesting, and potentially very useful.
I am curious about how you propose access to shared memory across fibers? What will happen if two fibers try to update a $GLOBALS variable at the same time? Or a property of the same object? How will developers manage that?
(I started writing this before Aaron sent a different response)
[Concurrency is not parallelism](text of https://blog.golang.org/waza-talk , not the video),
and this RFC isn't adding parallelism to php.
Instead, the RFC is a proposal to make concurrency easier.
The rfc announcement email says that "fibers exist within a single thread".
A fiber would have to explicitly release control to the scheduler after modifying a $GLOBALS variable, etc.
As I understand it, this proposal is similar to how concurrency works in node for code written in JS - https://stackoverflow.com/questions/29977049/how-does-concurrency-work-in-nodejs
(in that there's only one thread, but it's different in that scheduling is done manually)
Thanks,
- Tyson
Hi again Aaron,
I've been playing around with this for a bit, and I have some more
questions. I see you recently changed how the FiberScheduler
works,
making it final
and adding some "is" functions to match it more to a
regular fiber.
Since the FiberScheduler
is itself also a fiber, why does it need to be a
separate class? Why did you choose to go this way and make it "special"
instead of not just making a regular fiber into a scheduler in userland.
Could you have two or more schedulers? Could you get by without a
scheduler and call a fiber inside a fiber recursively?
Related to that, I noticed it was not possible to call Fiber::this()
from
within the scheduler, why is that? Is it not just another fiber? Or is
this to prevent it from being passed to another scheduler?
Alternatively, going the other way, instead of making the scheduler a
unique class that needs to be passed around, why not go the more
"traditional" PHP route and pattern it after
register_shutdown_function(callable $callback, mixed ...$args) : void
,
spl_autoload_register(callable $autoload_function = ?, bool $throw = true, bool $prepend = false) : bool
, and those type of functions? After all,
isn't it just a callback too? Something like
register_fiber_scheduler(callable $callback) : void
?
This would remove the need for a special scheduler class and the need for
passing the scheduler back to the Fiber::suspend()
. Each suspend()
call would bubble up through the registered scheduler callbacks. This
would allow competing schedulers to work nicer together, instead of one
scheduler having to finish before the higher up scheduler can run it's next
loop.
Either way, doesn't the fiber already know which scheduler it is in when it
suspends?
I think this would go along with simplifying it and keep the implementation
broad to allow for various userland implementations (as mentioned, such as
amphp and reactphp). But it probably doesn't simplify the C
implementation...
Anyways, something like this?
$fiber = Fiber::this();
$callbacks = [
fn() => $fiber->resume("Test"),
];
register_fiber_scheduler(function() use ($callbacks) {
foreach ($callbacks as $callback) {
$callback();
}
});
$value = Fiber::suspend();
echo "After resuming main fiber: ", $value, "\n"; // Output: After
resuming main fiber: Test
Btw, this is just me vomiting my thoughts, I don't know enough about fibers
to design it one way or the other, but I hope to understand it more as well
as give a few different perspectives on it.
Thanks,
Peter
Hello everyone!
I would like to introduce an RFC for adding full-stack fibers to PHP:
https://wiki.php.net/rfc/fibersFibers are primarily used to implement green-threads or coroutines for
asynchronous I/O. Fibers are similar to threads, except fibers exist within
a single thread and require cooperative scheduling of the fibers by the
process. Since fibers do not require a full CPU context switch, they are
lightweight and more performant than multi-processing or threading for
awaiting I/O.An implementation as an extension is at https://github.com/amphp/ext-fiber
Fibers are a complex feature. The RFC contains many examples and links to
code using fibers to help explain and demonstrate what is possible, however
I’m certain many more questions and concerns will arise. Looking forward to
feedback and discussion.Aaron Piotrowski
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Peter,
I've been playing around with this for a bit, and I have some more questions. I see you recently changed how the
FiberScheduler
works, making itfinal
and adding some "is" functions to match it more to a regular fiber.Since the
FiberScheduler
is itself also a fiber, why does it need to be a separate class? Why did you choose to go this way and make it "special" instead of not just making a regular fiber into a scheduler in userland.
FiberScheduler
is “special” because user code is not in control of suspending/resuming the underlying fiber, so FiberScheduler
is a different class from Fiber
without those methods. Internally a user fiber and scheduler fiber are similar, but I wanted to differentiate them in user code.
FiberScheduler
recently changed from an interface to a class because we discovered that automatically creating a scheduler fiber internally would make it difficult for adaptors or wrappers of a FiberScheduler
to not create multiple internal scheduler fibers when there should only be a single scheduler fiber. The API largely works the same, but now the creation of the scheduler fiber is explicit in user code instead of done internally. This way adaptors or wrappers can return a single FiberScheduler
instance. More code is required in user libraries, but offers greater flexibility.
Could you have two or more schedulers?
You can have two or more schedulers in a single script. Only one can ever be running at a single time.
Could you get by without a scheduler and call a fiber inside a fiber recursively?
This design requires a scheduler fiber to be entered between suspending one user fiber and resume another user fiber. User fibers are designed to be independent. If two users fibers need to communicate, they should use something similar to Go’s channels to exchange data.
Related to that, I noticed it was not possible to call
Fiber::this()
from within the scheduler, why is that? Is it not just another fiber? Or is this to prevent it from being passed to another scheduler?
A scheduler fiber cannot be suspended or resumed by user code so it is not useful to get a reference to that fiber.
Alternatively, going the other way, instead of making the scheduler a unique class that needs to be passed around, why not go the more "traditional" PHP route and pattern it after
register_shutdown_function(callable $callback, mixed ...$args) : void
,spl_autoload_register(callable $autoload_function = ?, bool $throw = true, bool $prepend = false) : bool
, and those type of functions? After all, isn't it just a callback too? Something likeregister_fiber_scheduler(callable $callback) : void
?This would remove the need for a special scheduler class and the need for passing the scheduler back to the
Fiber::suspend()
. Eachsuspend()
call would bubble up through the registered scheduler callbacks. This would allow competing schedulers to work nicer together, instead of one scheduler having to finish before the higher up scheduler can run it's next loop.
The scheduler to be entered is specific to the code calling Fiber::suspend()
. Registering a global scheduler would require only a single scheduler to be used in a script. Only a single scheduler is entered on a call to Fiber::suspend()
, not multiple schedulers. Registering schedulers or wrapping application code in boilerplate depending on the library being used is something this API is attempting to avoid.
Either way, doesn't the fiber already know which scheduler it is in when it suspends?
No, a fiber can potentially use different schedulers at different suspend points. The scheduler that starts a fiber does not necessarily need to be the only scheduler that suspends the fiber.
Hopefully that helps in understanding how the API works. Please take a look at how amphp v3 uses fibers in these examples https://github.com/amphp/amp/tree/v3/examples/pipeline or in react-fiber https://github.com/trowski/react-fiber/tree/master/examples where the Fiber API is handled by the library rather than “application” code.
Cheers,
Aaron Piotrowski
Hello everyone!
I would like to introduce an RFC for adding full-stack fibers to PHP:
https://wiki.php.net/rfc/fibersFibers are primarily used to implement green-threads or coroutines for
asynchronous I/O. Fibers are similar to threads, except fibers exist within
a single thread and require cooperative scheduling of the fibers by the
process. Since fibers do not require a full CPU context switch, they are
lightweight and more performant than multi-processing or threading for
awaiting I/O.An implementation as an extension is at https://github.com/amphp/ext-fiber
Fibers are a complex feature. The RFC contains many examples and links to
code using fibers to help explain and demonstrate what is possible, however
I’m certain many more questions and concerns will arise. Looking forward to
feedback and discussion.Aaron Piotrowski
Hi Aaron,
this is a very interesting and welcome piece of functionality. I have gone
through the RFC a few times now, it have never thought about or worked with
fibers before, additional feedback will be forthcoming once I grasp the
details more.
From my POV the effects on other extensions are the most important factor,
you already have a section with that for Xdebug, Parallel, and pcov. But
how does this affect Profilers that manage their own stack of frames,
either all function calls or specifically selected ones. I.e. xhprof,
tideways, datadog, newrelic and so on.
At the moment any PHP Profiler only has to manage a single stack of "open
frames". With Fibers for each fiber a new stack must be opened.
Does an extension know what the "active" fiber is so that from a
zend_execute_data I know on which stack of open frames I need to push a new
frame?
Could you add a section to the RFC explaining how a switch between fibers
works in terms of "the next" and "previous" zend_execute_data that is run?
This would also be interesting to understand how stack traces work, for
example debug_print_backtrace.
--
To unsubscribe, visit: https://www.php.net/unsub.php
Hi Aaron,
this is a very interesting and welcome piece of functionality. I have gone
through the RFC a few times now, it have never thought about or worked with
fibers before, additional feedback will be forthcoming once I grasp the
details more.From my POV the effects on other extensions are the most important factor,
you already have a section with that for Xdebug, Parallel, and pcov. But
how does this affect Profilers that manage their own stack of frames,
either all function calls or specifically selected ones. I.e. xhprof,
tideways, datadog, newrelic and so on.
Hi Benjamin,
Sorry for the bit of a delay in replying. I’ve been busy the last few days.
Profilers that manage their own stack of frames will have to be modified to account for fibers. The extension currently provides an API to access the current fiber and uniquely identify each different fiber.
The internal API for this will need further discussion amongst the rest of the internals contributors and hopefully the authors of those extensions. I omitted any API for this from the RFC as it does not affect user code.
At the moment any PHP Profiler only has to manage a single stack of "open
frames". With Fibers for each fiber a new stack must be opened.Does an extension know what the "active" fiber is so that from a
zend_execute_data I know on which stack of open frames I need to push a new
frame?
Four functions are currently provided for determining the current executing fiber.
zend_fiber *zend_get_root_fiber()
zend_fiber *zend_get_current_fiber()
zend_long zend_fiber_get_id(zend_fiber *fiber)
zend_long zend_fiber_get_current_id()
These allow you to get the root and current fiber as well as the ID associated with the fiber.
The fiber ID is unique to the process and is never reused, so it can be used to determine which open stack frame to push a frame.
Could you add a section to the RFC explaining how a switch between fibers
works in terms of "the next" and "previous" zend_execute_data that is run?
This would also be interesting to understand how stack traces work, for
example debug_print_backtrace.
I added a brief section under FAQs entitled "How are execution stacks swapped?”, https://wiki.php.net/rfc/fibers#how_are_execution_stacks_swapped
Backtraces are currently limited to including only the currently executing fiber. It may be possible to include backtraces of fibers further down the execution stack, but I had issues when trying to implement this in the extension during shutdown due to stacks being freed. Something I think can be addressed if adding to core with the help of someone more familiar with how references to these stacks are kept and what should be modified in the functions generating backtraces.
Cheers,
Aaron Piotrowski