协程切换开销远低于进程切换,本质是用户态栈操作而非内核态上下文切换:协程仅保存/恢复寄存器和用户栈(几十纳秒),进程需内核介入并切换地址空间、页表、文件描述符等(微秒至毫秒级)。

协程切换开销远低于进程切换,本质是用户态栈操作 vs 内核态上下文切换
协程切换不涉及操作系统内核调度,只是保存/恢复寄存器和用户栈,通常几十纳秒;进程切换必须由内核介入,要保存整个地址空间、页表、文件描述符、信号处理等,耗时在微秒到毫秒级。实际压测中,Swoole 协程每秒可完成千万级切换,而 fork 出的子进程每秒最多几千次创建+销毁。
Coroutine::create() 和 pcntl_fork() 的资源消耗对比
调用 Coroutine::create() 仅分配几 KB 栈内存(默认 128KB,可调),无系统调用;pcntl_fork() 会复制父进程的整个虚拟内存空间(写时复制除外)、打开的 fd、信号掩码等,即使空进程也需数微秒以上。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
-
Coroutine::create():纯 PHP 层内存分配,无 syscall,失败只因内存不足或栈溢出 -
pcntl_fork():触发fork()系统调用,受/proc/sys/kernel/pid_max和RLIMIT_NPROC限制,频繁调用易触发EAGAIN - 协程间共享变量无需加锁(单线程内串行调度),进程间共享需 IPC + 同步机制
为什么 co::sleep() 不阻塞整个进程,而 sleep() 会
co::sleep() 是协程感知的挂起:当前协程让出控制权,调度器立即切走,其他协程继续运行;sleep() 是同步系统调用,会让当前**整个进程**(含所有线程)休眠——在 Swoole Worker 进程里,这等于阻塞全部协程。
- 错误写法:
sleep(1)在协程中 → 整个 Worker 进程卡死 1 秒 - 正确写法:
co::sleep(1)→ 仅当前协程暂停,其余协程照常执行 - 底层差异:前者调用
nanosleep(),后者由 Swoole hook 成非阻塞定时器回调
协程切换不等于无成本,高频 yield 仍可能拖慢性能
虽然协程切换快,但过度拆分逻辑(比如在循环里每轮都 co::sleep(0))会放大调度器开销。Swoole 默认协程栈为 128KB,大量协程会吃光内存;而进程虽重,但每个进程有独立内存边界,OOM 风险更可控。
- 协程栈大小通过
swoole_set_hook(SWOOLE_HOOK_ALL)后的coroutine.stack_size配置,小了易栈溢出,大了浪费内存 - 进程崩溃不会波及兄弟进程,协程 panic(如未捕获异常)会终止整个 Worker 进程
- 调试难度:协程堆栈是动态拼接的,
debug_print_backtrace()显示不完整;进程 crash 可直接用gdb抓 core










