3v4l.org

run code in 300+ PHP versions simultaneously
<?php class FiberPool { /** @var Fiber[] */ private array $fibers = []; private int $max = 10; private array $results = []; public function __construct( private \Generator $generator, ) { } public function wait(): void { while ($this->fibers || $this->generator->valid()) { // Fill up the pending fibers while (count($this->fibers) < $this->max && $this->generator->valid()) { $this->startNextItem(); } foreach ($this->fibers as $key => $fiber) { // TBD: We could try/catch this and set the exception to the results array. if ($fiber->isSuspended()) { $fiber->resume(); } else if (!$fiber->isStarted()) { $fiber->start(); } if ($fiber->isTerminated()) { $this->results[$key] = $fiber->getReturn(); unset($this->fibers[$key]); $this->startNextItem(); } } // If we're in a fiber loop ourselves then suspend up the chain once per loop. if (Fiber::getCurrent()) { Fiber::suspend(); } } } public function getResults(): array { return $this->results; } private function startNextItem(): void { if ($this->generator->valid()) { $callable = $this->generator->current(); $this->fibers[$this->generator->key()] = new Fiber($callable); $this->generator->next(); } } } $consistentSuspend = function () { static $seed = [0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0]; return array_pop($seed); }; $example = new FiberPool((function () use ($consistentSuspend) { $output = array_combine(range('A', 'Z'), range(1,26)); foreach ($output as $key => $item) { echo 'generating ', $item, "\n"; yield $key => function () use ($consistentSuspend, $item) { echo 'starting ', $item, "\n"; while ($consistentSuspend()) { echo 'suspending ', $item, "\n"; Fiber::suspend(); } echo 'returning ', $item, "\n"; return $item; }; } })()); $example->wait(); print_r($example->getResults());
Output for 8.1.0 - 8.1.33, 8.2.0 - 8.2.29, 8.3.0 - 8.3.25, 8.4.1 - 8.4.12
generating 1 generating 2 generating 3 generating 4 generating 5 generating 6 generating 7 generating 8 generating 9 generating 10 generating 11 starting 1 returning 1 generating 12 starting 2 returning 2 generating 13 starting 3 suspending 3 starting 4 suspending 4 starting 5 suspending 5 starting 6 returning 6 generating 14 starting 7 suspending 7 starting 8 returning 8 generating 15 starting 9 suspending 9 starting 10 returning 10 generating 16 returning 3 generating 17 suspending 4 returning 5 generating 18 suspending 7 suspending 9 starting 11 suspending 11 starting 12 returning 12 generating 19 starting 13 suspending 13 starting 14 suspending 14 starting 15 suspending 15 returning 4 generating 20 returning 7 generating 21 returning 9 generating 22 returning 11 generating 23 suspending 13 suspending 14 returning 15 generating 24 starting 16 returning 16 generating 25 starting 17 suspending 17 starting 18 returning 18 generating 26 suspending 13 suspending 14 suspending 17 starting 19 returning 19 starting 20 returning 20 starting 21 returning 21 starting 22 returning 22 starting 23 suspending 23 starting 24 returning 24 starting 25 suspending 25 suspending 13 returning 14 returning 17 returning 23 returning 25 starting 26 suspending 26 returning 13 returning 26 Array ( [A] => 1 [B] => 2 [F] => 6 [H] => 8 [J] => 10 [C] => 3 [E] => 5 [L] => 12 [D] => 4 [G] => 7 [I] => 9 [K] => 11 [O] => 15 [P] => 16 [R] => 18 [S] => 19 [T] => 20 [U] => 21 [V] => 22 [X] => 24 [N] => 14 [Q] => 17 [W] => 23 [Y] => 25 [M] => 13 [Z] => 26 )

preferences:
67 ms | 412 KiB | 5 Q