根本原因是父进程未调用 swoole_process::wait() 回收,导致子进程退出后变僵尸并被系统强制回收;swoole_process 不自动 wait,必须显式循环调用 swoole_process::wait(false) 非阻塞回收。

为什么 swoole_process 启动后子进程立刻退出?
根本原因通常是父进程没调用 wait() 或 waitpid(),导致子进程变成僵尸进程后被系统回收。Swoole 的 swoole_process 默认不自动 wait,必须显式处理。
常见错误写法:$proc->start() 后直接继续往下跑,没管子进程生死;或者用了 pcntl_wait() 却忘了它只能捕获本进程创建的子进程(而 swoole_process 底层封装了 fork,需用 swoole_process::wait())。
- 正确做法:循环调用
swoole_process::wait(false),第二个参数设为false表示非阻塞,避免卡住主流程 - 若需精确控制数量,建议配合计数器 + 进程池管理逻辑,而不是依赖信号回调(
signal(SIGCHLD, ...)在 Swoole 主循环中不稳定) - 注意:在
onWorkerStart中创建子进程时,每个 worker 进程都会执行一遍,容易重复 fork——务必加if ($worker_id === 0)等条件限定
swoole_server 下如何安全地 fork 多个子进程并限流?
不能直接在 onReceive 里反复 new swoole_process,否则连接量一高就 fork 爆炸,内存和进程数双双失控。
核心思路是预启固定数量子进程(比如 4 个),用管道或消息队列做任务分发,主 server 只负责接收请求、投递任务,不参与实际业务计算。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 子进程启动后,立即调用
$process->useQueue()创建消息队列,或用msg_get_queue()手动管理,避免每次通信都新建 IPC 资源 - 投递任务前检查队列是否满(
msg_send返回 false 或抛 Warning),满了就丢弃或降级(如返回 503),别硬塞 - 子进程内不要调用
sleep()或阻塞 IO,必须用swoole_event_add()监听管道可读事件,保持异步响应能力
用 swoole_timer_tick 管理子进程生命周期靠谱吗?
不靠谱。定时器只运行在主线程/主 Worker 中,无法感知子进程内部状态,也不能跨进程 kill 或重启某个特定子进程。
真正可控的方式是父子进程间建立双向管道(pipe()),主进程通过写端发送指令(如 "reload"、"quit"),子进程用 stream_select() 或 swoole_event_add() 监听读端,收到即执行对应动作。
- 避免用信号(
posix_kill($pid, SIGUSR1))做控制——Swoole 会拦截部分信号,且多线程环境下信号传递不可靠 - 子进程退出前务必调用
posix_kill($parent_pid, SIGUSR2)主动通知父进程,否则父进程可能长期等不到wait()返回 - 如果子进程要执行耗时任务(如图像处理),建议设置超时:用
pcntl_alarm(30)+pcntl_signal(SIGALRM, ...),超时即 exit,防止单个任务拖垮整个池
并发数设多少才不翻车?
没有通用值。取决于子进程实际工作内容:纯 CPU 计算建议 ≤ CPU 核数;含 IO(如 curl、MySQL)可适当上浮,但超过 8–12 通常收益递减,反而因上下文切换加重负载。
更关键的是压测时观察两个指标:ps aux | grep your_proc | wc -l(真实进程数)和 cat /proc/sys/kernel/pid_max(系统 PID 上限)。很多线上事故不是代码问题,而是子进程泄漏导致 PID 耗尽,新请求连 fork 都失败。
- 务必在子进程入口处加
cli_set_process_title("php-worker:xxx"),方便用ps快速识别异常残留进程 - 所有
new swoole_process调用必须配套onExit回调或主动wait,漏一个就可能积累僵尸进程 - 开发期用
strace -f -e trace=fork,clone,waitpid -p $(pgrep -f "your_script.php")抓系统调用,比日志更能看清实际 fork/wait 是否匹配










