coroutinesystem::exec是协程安全的阻塞调用,挂起当前协程而非整个进程,返回[code, stdout, stderr]数组;而shell_exec等php原生函数会阻塞整个线程,破坏协程并发性,swoole中严禁使用。

CoroutineSystem::exec 是协程安全的阻塞调用
CoroutineSystem::exec 在 Swoole 协程环境中执行外部命令,会挂起当前协程而非整个进程,其他协程可继续运行。它返回一个包含 code、stdout、stderr 的数组,行为类似同步版的 proc_open 封装。
关键点在于:它**不继承父进程的文件描述符**(如已关闭的 stdin/stdout),且默认不走 shell 解析(即不支持 |、&&、变量展开等),传入的命令必须是完整可执行路径或确保在 $PATH 中,且参数需拆成数组传递:
[$code, $output, $error] = CoroutineSystem::exec('/bin/ls', ['-l', '/tmp']);
常见错误现象:Command not found(路径不对)、Argument list too long(参数超长未分片)、Permission denied(目标二进制无执行权限)。
shell_exec 是 PHP 原生函数,会阻塞整个线程
shell_exec 是 PHP 内置函数,底层调用 fork + execve,但在 Swoole 的协程上下文中使用它,会导致当前工作线程(thread)被完全阻塞 —— 所有运行在该线程上的协程都会卡住,破坏协程并发性。
它把整个字符串交给 /bin/sh -c 解释,支持管道、重定向、环境变量等 shell 特性:
$result = shell_exec('ps aux | grep php | wc -l');
但代价是:无法获取退出码、无法分离 stderr、无法控制超时、无法在协程中安全使用。Swoole 官方明确标注其为「非协程安全」。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
别混用:Swoole 协程里不能用 shell_exec
在 SwooleCoroutine 或 SwooleHttpServer 的回调中直接调用 shell_exec,轻则导致接口响应延迟(因为线程卡死),重则引发连接堆积、超时雪崩。尤其在高并发场景下,一个慢命令可能拖垮整条工作线程。
替代方案只有两个:
- 用
CoroutineSystem::exec替代,自行拼接管道逻辑(例如多次 exec + 文件临时中转) - 改用
CoroutineProcess启子进程并手动管理 I/O(适合复杂 shell 流程,但开发成本高)
注意:CoroutineSystem::exec 默认无超时控制,如需限制执行时间,必须配合 Coroutine::sleep + kill 自行实现,或升级到 Swoole 5.1+ 使用 timeout 参数(需确认编译时启用 --enable-sysvsem)。
exec 和 system 函数在协程中同样危险
PHP 原生的 exec、system、passthru 全部基于 fork,全部会阻塞线程,全部禁止在协程中使用。它们和 shell_exec 属于同一类风险函数 —— 表面看只是“执行命令”,实际是协程模型的硬性边界。
容易被忽略的一点:某些 Composer 包(比如旧版 symfony/process)在未显式配置为异步时,底层仍会调用 exec,接入前务必检查其运行模式。Swoole 环境下推荐直接使用 CoroutineSystem::exec 或封装好的 swow/process(如需更细粒度控制)。










