Swoole协程与传统PHP进程的核心区别在于:进程常驻(Worker启动一次永不退出)、请求非阻塞(协程IO挂起调度)、资源复用(连接池/类/配置仅初始化一次);而PHP-FPM每次请求重建进程、全量初始化、无共享资源。

要真正理解Swoole协程与传统PHP进程的区别,不能只看代码写法差异,得从进程是否常驻、请求是否阻塞、资源是否复用三个硬指标切入——比如同样执行100次数据库查询,PHP-FPM会新建100个进程并重复建立100次连接,而Swoole Worker进程只启动一次,所有协程共享同一个连接池。
进程生命周期:启动一次 vs 每次重建
在PHP-FPM中,每个HTTP请求都会触发fork一个新进程,该进程加载Zend引擎→初始化扩展→执行脚本→销毁全部内存,整个过程不可中断。哪怕返回纯文本“OK”,也要走完全部初始化流程。
在Swoole中,【Master进程启动后永不退出,Worker进程常驻内存】,所有PHP代码(包括vendor/autoload.php、new PDO()、Redis::connect())仅执行一次,后续请求直接复用已加载的类、已建立的连接、已解析的配置。
这导致一个关键后果:PHP-FPM里require_once('config.php')会执行100次,Swoole里只执行1次。
立即学习“PHP免费学习笔记(深入)”;
并发模型:协程调度 vs 进程抢占
方法一:PHP-FPM靠操作系统调度进程,100并发 ≈ 100个独立进程争抢CPU时间片,每次切换需内核介入,上下文开销大。
方法二:Swoole默认启用协程(Swoole\Runtime::enableCoroutine()),单个Worker进程内可同时运行数千协程;当协程遇到mysql_query()等IO操作时,自动挂起自己,调度器立刻切到另一个就绪协程执行,全程用户态完成,无系统调用开销。
【协程栈内存默认仅8KB~128KB,而PHP-FPM进程常驻内存动辄20MB+】,同样4核机器,Swoole可轻松跑8个Worker,FPM可能卡在16个就内存告急。
变量与资源隔离性
第一步:在PHP-FPM中声明static $counter = 0,两次独立HTTP请求分别打印该变量,结果始终为0——因为进程销毁后静态变量随内存清空。
第二步:在Swoole onRequest回调中定义static $counter = 0,每次请求执行$counter++并返回值,你会发现该变量在Worker进程内持续累加——【协程间不隔离静态变量,极易引发脏读】。
第三步:必须改用Swoole\Coroutine::getContext()或Co::getUid()做上下文隔离,或显式通过go(function() use ($data) { })传参,否则多个请求会共用同一份static数据。
注意:$_GET、$_POST、$_SERVER等超全局变量在Swoole中默认不可用,必须从$request->get、$request->post、$request->server显式获取。
IO处理方式:同步阻塞 vs 非阻塞协程化
PHP-FPM环境下,file_get_contents()、curl_exec()、mysqli_query()这类原生函数会阻塞当前进程,直到IO完成才继续执行下一行代码。
Swoole协程中,只要启用了协程化(Swoole\Runtime::enableCoroutine()),上述函数会自动hook为协程版——遇到IO等待时挂起当前协程,调度器立即切换至其他协程,等IO就绪再恢复执行。
但必须牢记:【未被hook的函数(如sleep()、usleep())仍会阻塞整个Worker】,必须改用co::sleep()替代。
数据库操作不能直接用PDO,必须用Swoole\Coroutine\MySQL或封装好的协程连接池,否则原生PDO会卡死Worker。



















