传负数或零容量时,swoole底层自动设为1,仍为带缓冲通道;close后pop先取尽数据再返回false,不抛异常。

Channel 构造时传负数容量会怎样
传 capacity ≤ 0 时,Swoole 底层会自动 fallback 到 1,不会报错也不会警告——这容易让人误以为“传 0 就是无缓冲”,但实际仍是带缓冲的通道。
- 源码位置在
swoole-channel.cc:132,ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE)后直接强制设为 1 - 若真要实现“无缓冲”语义(即同步通道),必须显式传
1,并配合push()/pop()成对调用,否则协程会挂起等待配对操作 - 测试时别只看是否抛异常,得用
chan->length()和chan->capacity()验证实际分配值
多个协程同时 push/pop 同一个 Channel 是否线程安全
是安全的,但仅限于单 Worker 进程内 —— Swoole 的 Channel 是协程安全(coroutine-safe),不是进程安全(process-safe)。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 底层用的是 per-coroutine 栈 + 全局锁(
mutex)保护队列结构,避免多协程并发修改内部指针出错 - 跨 Worker 进程访问同一个
Channel实例?不可能。每个 Worker 的Channel对象完全独立,PHP 层变量不共享 - 常见误用:在
onWorkerStart创建一个全局$chan = new Co\Channel(),然后期望所有请求协程都能往里面 push —— 实际上每个请求进来的协程拿到的是各自副本,数据根本收不到
Channel close() 后再 pop() 会返回什么
返回 false,且不会触发协程挂起;但要注意,close() 不会清空已有数据,已 push 未 pop 的值仍可读取。
-
close()只是标记通道关闭状态,后续push()会立即失败并返回false,而pop()会先尝试取完剩余数据,取尽后才返回false - 没有类似 Go 的 “closed channel panic”,也没有 PHP 异常抛出,全靠返回值判断,容易漏判
- 典型坑点:用
while ($data = $chan->pop()) { ... }会无限循环,因为pop()返回false在条件判断里等价于false,但若通道未 close 且无数据,它会挂起而非返回false—— 所以必须加超时或显式检查closed状态
为什么 Channel 不适合跨协程传递大对象
不是语法限制,而是内存模型决定的:Channel 内部拷贝的是 PHP zval 指针,但若对象含资源型属性(如 PDO、file handle、Swoole\Client),这些资源无法被序列化复制,会导致接收方拿到损坏句柄或空对象。
- 实测表现:push 一个含
new Swoole\Client()属性的对象,pop 出来后调用connect()直接 segfault - 真正安全的只有纯数据结构:数组、字符串、数字、不含资源的 stdClass 实例
- 替代方案:用
Co\Channel传 ID 或 key,再由接收协程查本地缓存/连接池获取真实对象










