优化Swoole协程需聚焦调度逻辑与阻塞规避:监控coroutine_peak_num判断协程池压力,确保max_coroutine×1.2≤fd上限防EMFILE;阶梯压测调参,每次增幅≤2000并监控RSS≤400MB;栈大小默认256KB,溢出先查阻塞调用,调大需设ZEND_SIGNAL=0;I/O必须深度协程化,CPU密集任务交由Task Worker处理。

优化 PHP 7.4 的 Swoole 协程,核心是让每个协程跑得稳、不卡、不爆内存,同时把并发潜力真正释放出来。重点不在堆参数,而在理清调度逻辑、规避阻塞陷阱、匹配业务水位。
确认协程真实负载与系统瓶颈
别凭感觉调参,先看数据:
- 运行中调用 swoole_get_status(),重点关注
coroutine_peak_num—— 若它长期接近或等于max_coroutine,说明协程池已满,新请求排队等待; - 执行
cat /proc/$(pidof php)/limits | grep "Max open files"查当前进程文件描述符上限; - 确保 max_coroutine × 1.2 ≤ fd 上限,否则会因拿不到 socket 句柄报 EMFILE 错误,而非内存不足。
安全上调 max_coroutine:阶梯压测 + RSS 监控
默认 3000 太保守,但盲目拉高极易 OOM:
- 从 3000 起步,用 500 并发压测,观察
coroutine_peak_num是否稳定在 2000 以下; - 若峰值频繁触达 2800+,上调至 5000,再压测;
- 每次增幅 ≤ 2000,且必须监控单 worker 的 RSS 内存 —— 超过 400MB 立即回退;
- 当
coroutine_peak_num不再随并发线性增长,而是趋于平台期,该值即为当前业务下的安全上限。
谨慎调整 coroutine_stack_size
栈大小不是越大越好,错误设置反而引发静默崩溃:
立即学习“PHP免费学习笔记(深入)”;
- 遇到
coroutine stack overflow,先检查代码:是否用了sleep()、usleep()或未设 timeout 的 cURL?这些阻塞调用会让协程挂起期间持续占栈,本质是逻辑问题,不是栈太小; - 确认无阻塞调用后仍溢出,可从默认 256KB 逐步试到 512KB;
- 只要调大栈,就必须同步设置环境变量 ZEND_SIGNAL=0;
- 严禁降至 128KB 以下,Swoole 6.1.1 及后续版本对此有严格校验。
深度协程化 I/O,避免隐式阻塞
Worker 进程卡顿的主因不是 CPU,而是未协程化的同步 I/O:
- 所有数据库操作必须用 Swoole\Coroutine\MySQL 或连接池封装,禁用 PDO/mysqli 同步驱动;
- HTTP 请求必须走 Swoole\Coroutine\Http\Client,不要用 curl_exec 或 Guzzle 同步模式;
- Redis 操作必须用 Swoole\Coroutine\Redis,而非 phpredis 扩展;
- 文件读写优先用 Swoole\Coroutine\FileSystem,避免
fopen()阻塞。
合理使用 Task Worker 分离重负载
协程解决的是 I/O 等待问题,但对 CPU 密集型任务(如图像处理、加密解密、复杂计算)无效:
- 将这类操作通过
$server->task()投递到独立的 Task Worker 进程; - 配置
task_worker_num时参考 CPU 核数,一般设为cpu_count - 1; - 确保
onTask回调中不出现任何阻塞调用,否则 Task Worker 自身也会卡住。
不复杂但容易忽略。



















