记录 Fiber 初体验
class Coroutine
{
private $fibers = [];
private $scheduler;
public function __construct()
{
$this->scheduler = new Scheduler;
}
public function create(callable $func, ...$args)
{
$fiber = new Fiber(function () use ($func, $args) {
try {
call_user_func($func, ...$args);
} catch (Throwable $e) {
echo 'Exception: ' . $e->getMessage() . PHP_EOL;
}
});
$fiber->start();
array_push($this->fibers, $fiber);
}
public function run()
{
while (!empty($this->fibers)) {
$fiber = array_shift($this->fibers);
if ($fiber->isStarted()) {
$this->scheduler->add($fiber);
}
}
while ($this->scheduler->isEmpty()) {
$fiber = $this->scheduler->get();
$fiber->resume();
if ($fiber->isSuspended()) {
$this->scheduler->add($fiber);
}
}
}
}
class Scheduler
{
private $queue = [];
public function add(Fiber $fiber)
{
array_push($this->queue, $fiber);
}
public function get(): Fiber
{
$fiber = array_shift($this->queue);
return $fiber;
}
public function isEmpty(): bool
{
return !empty($this->queue);
}
}
// 使用示例
function task1() {
for ($i = 0; $i <= 5; $i++) {
echo "Task1: " . $i . PHP_EOL;
Fiber::suspend();
}
}
function task2() {
for ($i = 0; $i < 10; $i++) {
echo "Task2: " . $i . PHP_EOL;
Fiber::suspend();
}
}
$coroutine = new Coroutine;
$coroutine->create('task1');
$coroutine->create('task2');
$coroutine->run();
需要注意的是,在 PHP 8 中,Fiber 类为实验性特性,仍然存在一些限制和不足(如无法控制协程数量、无法轻松地进行异步 IO 操作等)