<?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