send_yield 并不存在于 Swoole 任何稳定版本中;send 是同步非阻塞调用,返回 true/null/false 表示不同发送状态,不挂起协程,背压需手动控制。
send_yield 不是 Swoole 的公开 API,它并不存在于任何稳定版本的 Swoole(包括 5.x 和 6.x)中。你很可能混淆了几个概念:协程挂起行为、send 的返回值语义、以及某些旧版文档或社区误传的命名。
send 在发送缓冲区满时的真实表现send 是同步非阻塞调用,它的行为与底层 socket 发送缓冲区状态强相关:
true:数据已成功写入操作系统 socket 发送缓冲区(注意:不是发到对端)null:数据暂存于 Swoole 应用层缓冲区,等待下一次 reactor 轮询时再尝试刷入 socket 缓冲区false:发送失败,常见原因包括客户端断连、fd 无效、或应用层缓冲区也满了(默认上限 2MB)缓冲区满 ≠ 程序卡死。Swoole 内部会把未发出的数据暂存在连接对象的应用层缓冲区,并在下一轮事件循环中重试。
你无法靠“加 yield”来“等它发完”——因为 send 本身不挂起协程,它只是个立即返回的函数。
send_yield?这个说法通常来自两类误解:
sendwait 当成 send_yield:sendwait 是阻塞式发送(底层调用 write() 直到写完或出错),会真正让当前协程等待,但它不感知缓冲区水位,也不做流量控制,容易拖垮整个协程调度器,生产环境应避免使用while ($server->send($fd, $data) === null) { Co::sleep(0.001); },这其实是在模拟背压等待,但效率低、精度差、且掩盖了根本问题onBufferFull 回调,在连接缓冲区快满时暂停投递新数据(比如暂停推送、降低心跳频率)buffer_high_watermark 和 buffer_low_watermark 配合 onBufferFull/onBufferEmpty 实现闭环控制send 数据不要超过 64KB,避免触发内核分片或应用层缓冲区膨胀recv),再快的 send 也无意义;此时应考虑业务层 ACK 或滑动窗口机制send 从不自动 yield,也不会因缓冲区满而挂起协程——它只返回 null 表示“这次没发出去,我记下了,下次再试”。真正的背压控制必须由你显式设计,而不是依赖一个不存在的 send_yield。