You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP Fiber简单示例运行异常,请求排查问题原因

问题:PHP Fiber示例运行异常排查

我尝试运行一个简单的PHP Fiber示例,但运行结果不符合预期,首次使用Fiber,不清楚问题出在哪。

预期输出

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

问题分析

  1. 全局变量未正确引用:fiber_await函数内的$fibers[]是局部变量,没有修改全局的$fibers数组,导致后续遍历的是空数组,逻辑完全走不下去。
  2. 主线程非法调用suspend:fiber_await在主线程(非Fiber上下文)中调用\Fiber::suspend(),PHP规定只有在Fiber内部才能挂起自身,主线程作为初始执行上下文无法被挂起,直接抛出FiberError。
  3. 调度逻辑错误:原代码试图用fiber_await来管理Fiber,但这个函数的设计逻辑完全错误,应该由主线程作为调度器,统一控制所有Fiber的唤醒和状态检查。

修正后的代码

$fibers = [];

// 添加Fiber 1
$fibers[] = new \Fiber(function(){
    while(true){
        echo "Fiber 1 is working!\n";
        \Fiber::suspend();
    }
});

// 添加Fiber 2
$fibers[] = new \Fiber(function(){
    while(true){
        echo "Fiber 2 is working!\n";
        \Fiber::suspend();
    }
});

// 添加Fiber 3
$fibers[] = new \Fiber(function(){
    for($i=0; $i<2; $i++){
        echo "Fiber 3 is working ($i)!\n";
        \Fiber::suspend();
    }
    echo "Fiber 3 completed!\n";
});

// 启动所有Fiber
foreach ($fibers as $fiber) {
    $fiber->start();
}

$j = 0;
while (!empty($fibers)) {
    echo "\niteration: $j\n";
    // 遍历并过滤已终止的Fiber
    $fibers = array_filter($fibers, function(\Fiber $fiber) {
        if (!$fiber->isTerminated()) {
            if ($fiber->isSuspended()) {
                $fiber->resume();
            }
            return true;
        }
        return false;
    });
    
    echo "(1 sec sleep)\n";
    sleep(1);
    $j++;
}

修正说明

  1. 直接将所有Fiber实例存入全局$fibers数组,避免作用域问题。
  2. 主线程作为调度器,先启动所有Fiber,然后在循环中逐个检查状态:未终止的Fiber如果处于挂起状态就唤醒它,已终止的则从数组中移除。
  3. 每次迭代完成后sleep 1秒,符合预期的输出节奏。

内容的提问来源于stack exchange,提问作者clarkk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 00:01:39