generator本质不是协程,而是php实现协程的底层载体;只有用yield+send()+throw()构建双向通信时才进入协程范畴,其内存恒定(o(1))因只存执行状态而非数据,不可序列化是设计使然,且需配合调度器或扩展才能实现真正协程。

Generator 本质不是协程,但它是 PHP 实现协程的底层载体;真正在用 yield + send() + throw() 构建双向通信时,才进入协程范畴。多数人误把“能 yield”等同于“在写协程”,结果卡在单向数据流里。
为什么 Generator 对象内存恒定(O(1))?
它不存数据,只存执行状态:当前行号、局部变量值(如 $i)、调用栈帧指针。每次 foreach 取下一个值,内核恢复该状态,跑一段到下一个 yield 就停。
-
range(1, 1000000)会分配约 100MB 内存存整数数组;xrange(1, 1000000)生成的Generator对象仅占 ~800 字节 - PHP 7.4+ 中,
Generator对象不可序列化,因为状态无法跨请求持久化——这是设计使然,不是 bug - 不要在
Generator函数里做耗时 I/O(如file_get_contents()),否则会阻塞整个迭代,失去“轻量”意义
send() 不是“传参”,是恢复并注入值
send() 必须在 Generator 暂停后调用,且目标必须是带参数的 yield 表达式,例如 $value = yield $default;。直接 yield $x 后调用 send() 会抛 Exception: Cannot send an array here。
- 正确模式:
function co() { $a = yield 1; echo $a; },然后$g = co(); $g->current(); $g->send('hello'); -
send()触发的是“恢复执行 + 赋值给左侧变量”,不是函数参数传递 - 首次调用
send()前必须先调用current()或next()让生成器走到第一个yield处,否则报错
协程 ≠ 并发,别指望靠 Generator 自动并发
原生 Generator 是协作式调度,没有自动挂起/唤醒机制。你得自己写调度器,或依赖 Swoole/ReactPHP 等扩展封装好的协程运行时。
- 纯 PHP 层用
yield写的“协程”,只是语法糖,仍是单线程顺序执行 - 真正异步 IO(如 MySQL 查询不阻塞)需要底层扩展支持,
Generator本身不提供 IO 多路复用能力 - 若混用
sleep()、fgets(STDIN)等同步阻塞调用,整个协程调度会卡死
yield 却没看到性能提升”,其实是忘了把耗时操作替换为非阻塞版本,或者误以为 PHP 解释器会自动调度多个 Generator 并发跑。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











