PHP 8.1 的 Fiber 在单 OS 线程内协作式调度,通过 suspend/resume 切换执行上下文,不创建新线程、不触发系统调用,仅保存/恢复栈与寄存器,适用于 I/O 密集型非阻塞场景。

Fiber 的执行永远只在一个 OS 线程里
PHP 8.1 的 Fiber 不会创建新操作系统线程,它只是在当前 PHP 进程的**唯一主线程**内切换执行上下文。无论你启动 10 个还是 100 个 Fiber,它们共享同一个 OS 线程、同一块内存空间、同一个 Zend 引擎实例。这和 pthread 或多进程(pcntl_fork)有本质区别——后者确实会派生新线程或进程,而 Fiber 只是“换栈不换线程”。
常见错误现象:Fiber::suspend() 后主流程继续运行,你以为“并发执行”了,其实只是控制权交还给了主协程;所有 Fiber 实例的 isRunning() 永远不会同时为 true,因为 CPU 时间片只属于当前正在 resume() 的那一个。
- 调用
Fiber::start()不触发系统调用,无上下文切换开销 -
Fiber::getCurrent()返回的永远是当前正在跑的那个Fiber实例,哪怕它刚被resume()进来 - 没有线程安全问题?错——共享变量仍需手动保护,因为不是线程隔离,而是**竞态发生在同一栈切换点**
Fiber::suspend() 不会让出 CPU,只是让出控制权
Fiber::suspend() 的作用不是“休眠当前 Fiber”,而是**立即中断当前执行流,把控制权交还给它的调用者(通常是主 Fiber 或调度器)**。它不 sleep、不 wait、不阻塞 OS 调度器,底层只是保存寄存器和栈指针,然后跳转回上层调用栈。
使用场景:适合封装 I/O 操作(如 cURL、PDO 查询),但必须配合事件循环(比如 ext-uv 或 Swoole\Coroutine)才能真正实现非阻塞——否则你 suspend() 之后啥也不做,只是卡在那儿等别人 resume(),跟同步代码没区别。
立即学习“PHP免费学习笔记(深入)”;
- 单独用
Fiber+sleep(1)不会并发,只会让整个进程停 1 秒 -
Fiber::suspend()返回值会被start()或resume()的返回值捕获,别指望它自动触发回调 - 如果调度器忘了
resume()某个 Fiber,它就永远挂起,变成内存泄漏点
Fiber 和 Generator 的关键差异在哪
Generator 只能在 yield 处暂停,且只能从生成器函数内部 yield,调用栈深度受限;Fiber 则可以在任意嵌套层级中调用 Fiber::suspend(),哪怕在第 5 层函数里、在闭包里、在依赖库的方法里——只要那个方法是你放进 Fiber 闭包里执行的。
参数差异:Generator::send() 是向 yield 表达式传值,而 Fiber::resume($value) 是向 Fiber::suspend() 的返回值赋值,语义更接近函数调用传参。
-
Generator无法跨函数边界 suspend(比如 A→B→C,C 里 yield,A 拿不到 C 的状态) -
Fiber的getReturn()只能在终止后调用,而Generator的getReturn()在valid() === false后才可用 -
Fiber::throw()可以向挂起点抛异常,Generator的throw()仅限于未关闭状态,且传播路径更脆弱
为什么 Fiber 不能替代多线程处理 CPU 密集型任务
因为 Fiber 是协作式调度,不是抢占式。一个进入死循环或密集计算的 Fiber(比如 for ($i = 0; $i )会一直霸占 CPU,其他 <code>Fiber 根本没机会被 resume() ——除非它自己主动调用 Fiber::suspend(),或者你在循环里手动插入调度点(比如检查某个标志位并 suspend())。
性能影响:Fiber 对 CPU-bound 场景几乎零优化,反而可能因频繁 suspend/resume 增加开销;它真正的价值在 I/O-bound 场景,靠事件驱动+调度器把等待时间腾出来跑别的 Fiber。
- 别试图用 Fiber 跑图像压缩、加密解密、大数组排序——这些该交给
pcntl或 Swoole 的子进程 -
Fiber::isSuspended()和Fiber::isRunning()是调试用的,别在热路径里反复查状态 - 嵌套 Fiber(比如一个 Fiber 里 new 另一个 Fiber)可行,但栈空间叠加,容易触发
Stack overflow,PHP 默认栈大小没变
resume(),会抛 FiberException(比如对已终止的 Fiber 调用 resume())。务必先用 isSuspended() 或 isRunning() 守卫。**



















