Fiber 本身不实现高并发,仅提供挂起/恢复能力;必须配合非阻塞 I/O 和事件循环才能真正实现高并发,否则仍是同步阻塞模型。

Fibers 本身不直接实现高并发,它只是提供挂起/恢复能力;真正实现高并发必须配合非阻塞 I/O 和事件循环,否则仍是同步阻塞模型。
为什么单独用 Fiber::suspend() 无法提升并发能力
很多人误以为只要把代码包进 Fiber 就自动异步了。事实是:Fiber::suspend() 只是交出控制权,但若后续操作(如 file_get_contents()、mysqli_query())仍是阻塞调用,主协程线程依然卡住,其他 Fiber 无法调度。
- 阻塞 I/O 调用会让整个线程停住,Fiber 无法“并发”,只能“顺序挂起”
-
Fiber的价值在于“可中断”,而非“自动非阻塞” - 没有事件循环驱动时,
resume()必须由你手动触发——这和写回调没本质区别
必须搭配非阻塞 I/O 扩展才能发挥实效
PHP 原生不提供非阻塞 socket 或数据库驱动,所以必须依赖扩展。常见组合有:
-
Swoole:自带协程运行时,swoole_coroutine_mysql等 API 默认非阻塞,Fiber可直接与之协作 -
ext-uv+ReactPHP:基于 libuv 的异步 I/O,需手动在Fiber中监听 uv 事件并resume() -
Amp:PHP 原生协程框架,内部已封装Fiber调度逻辑,对用户屏蔽底层细节
例如用 Swoole 启动一个协程 MySQL 查询:
立即学习“PHP免费学习笔记(深入)”;
$fiber = new Fiber(function () {
$mysql = new Swoole\Coroutine\MySQL();
$res = $mysql->connect(['host' => '127.0.0.1', 'user' => 'root']);
// 此处不阻塞线程,Fiber 自动挂起,等待 I/O 完成后由 Swoole 恢复
$stmt = $mysql->query('SELECT sleep(1), "done"');
return $stmt;
});
$fiber->start(); // 不会卡住主线程
Fiber 的状态管理容易被忽略的细节
一个 Fiber 实例不是无限可 resume 的,它的生命周期很明确,稍不注意就会抛出 FiberError:
- 已
start()但未suspend()就直接resume()→ 报错"Cannot resume a fiber that is not suspended" - 已执行完毕(函数返回或异常终止)再调用
resume()→ 报错"Cannot resume a dead fiber" -
Fiber::suspend()只能在 Fiber 内部调用,外部调用会 fatal error
建议始终检查状态:
if ($fiber->isSuspended()) {
$fiber->resume($data);
} elseif ($fiber->isTerminated()) {
throw new RuntimeException('Fiber already finished');
}
真正难的不是写 Fiber,而是设计调度器:谁来监听 I/O 完成?谁决定何时 resume() 哪个 Fiber?这部分逻辑一旦手写,复杂度陡增——这也是为什么生产环境几乎都选 Amp 或 Swoole,而不是裸用 Fiber。



















