I'm trying to make some simple fibers work, but doesn't seem to go as expected. What am I missing here? Have never worked with fibers before
The output I expected:
iteration: 0
Fiber 1 is working!
Fiber 2 is working!
Fiber 3 is working (0)!
(1 sec sleep)
iteration: 1
Fiber 1 is working!
Fiber 2 is working!
Fiber 3 is working (1)!
(1 sec sleep)
iteration: 2
Fiber 1 is working!
Fiber 2 is working!
Fiber 3 completed!
(1 sec sleep)
iteration: 3
Fiber 1 is working!
Fiber 2 is working!
(1 sec sleep)
...
$fibers = [];
// add fiber 1
fiber_await(new \Fiber(function(){
while(true){
echo "Fiber 1 is working!\n";
\Fiber::suspend();
}
}));
// add fiber 2
fiber_await(new \Fiber(function(){
while(true){
echo "Fiber 2 is working!\n";
\Fiber::suspend();
}
}));
// add fiber 3
fiber_await(new \Fiber(function(){
for($i=0; $i<2; $i++){
echo "Fiber 3 is working ($i)!\n";
\Fiber::suspend();
}
echo "Fiber 3 completed!\n";
}));
$j = 0;
foreach($fibers as $i => &$pair){
echo "iteration: $j\n";
$parent = $pair[0];
if($parent->isTerminated()){
unset($fibers[$i]);
}
elseif($parent->isSuspended()){
$parent->resume();
}
sleep(1);
$j++;
}
function fiber_await(\Fiber $child): mixed{
$fibers[] = [\Fiber::getCurrent(), $child];
$child->start();
while(!$child->isTerminated()){
$child->resume();
\Fiber::suspend();
}
return $child->getReturn();
}
Fiber 1 is working!
Fiber 1 is working!
Fatal error: Uncaught FiberError: Cannot suspend outside of a fiber in Standard input code:46
Stack trace:
#0 Standard input code(46): Fiber::suspend()
#1 Standard input code(12): fiber_await(Object(Fiber))
#2 {main}
thrown in Standard input code on line 46
There are a couple of general (not fiber-specific) logic errors here:
$fibers
isn't declared global in the fiber_await
function, so the outer code will always have an empty array$j
look like they're supposed to be part of some outer do...while
loop rather than the foreach
- at the moment, each fiber would be iterated exactly once by that loopThe first fiber-specific problem is that you're calling $child->start();
which echoes "Fiber 1 is working!" and suspends the fiber; then you immediately call $child->resume();
which echoes "Fiber 1 is working!" again, and suspends it again.
After that, you call \Fiber::suspend()
, but the fiber has already suspended itself, and you're back in top-level code. So you get an error about trying to suspend when no fiber is currently running. That whole loop makes no sense: you don't want to immediately exhaust the fiber at this stage, just store it for later.
For the same reason, \Fiber::getCurrent()
will always return null
, because you're not nesting the fibers - they're all siblings, with the top-level stack as their parent. As such, if you fixed the other problems, all the references to $parent
in the foreach
loop will give errors. You actually want to check and resume the child, which is $pair[1]
; or, since you don't need $parent
right now, just use $fibers[] = $child;