必须调用Swoole\Runtime::enableCoroutine(true)启用协程,否则sleep等操作会阻塞整个Worker进程;配置、扩展加载、协程变量隔离及资源复用等细节均需严格遵循协程编程规范。

协程不启用,sleep() 会直接阻塞整个 Worker 进程
这是新手跑第一个 TCP/HTTP 示例时最常踩的坑:写了个 sleep(3) 或 file_get_contents(),结果整个服务卡住,所有并发请求都排队等它——因为默认情况下 Swoole 的 IO 是同步阻塞的,sleep 不是“让当前协程睡”,而是让整个线程停摆。
- 必须在启动服务前调用
Swoole\Runtime::enableCoroutine(true),否则所有协程 API(包括Swoole\Coroutine\sleep、go)都无效 - 该设置需在
new Swoole\Http\Server之前执行,放在on("request")回调里无效 - PHP 8.1+ 开启后,部分扩展(如某些 Redis 客户端)若未适配协程,可能触发
Segmentation fault,建议优先用Swoole\Coroutine\Redis
swoole_http_server 和 swoole_server 别混用配置项
新手复制代码时容易把 HTTP 服务器的配置直接套到原始 swoole_server 上,比如给 TCP 服务器加 'http_parse_post' 或在 on("request") 里处理非 HTTP 数据——这会导致运行时报错或静默失败。
-
swoole_http_server是swoole_server的子类,自带 HTTP 协议解析;裸swoole_server只收发原始字节流,需自己实现协议 -
worker_num对两者都有效,但http_compression、enable_static_handler等仅 HTTP 服务器支持 - 用
telnet 127.0.0.1 9501测试时,如果连上就断开,大概率是用了 HTTP 服务器却发了非 HTTP 请求(如纯字符串)
php.ini 加了 extension=swoole.so 却提示 “Class not found”
不是扩展没装,而是 PHP CLI 和 Web SAPI(如 FPM)用的是两套 php.ini。你在终端 php -m | grep swoole 看到了,但 php-fpm 可能根本没加载。
- 查 CLI 配置路径:
php --ini;查 FPM 配置路径:php-fpm -i | grep "Loaded Configuration File" - 确保两个环境的
php.ini都写了extension=swoole.so,且扩展文件真实存在(通常在/usr/lib/php/*/swoole.so或$(php-config --extension-dir)/swoole.so) - 改完
php.ini后,CLI 不用重启,但 FPM 必须执行sudo systemctl reload php-fpm(或对应命令)
用 go() 启动协程,但变量修改不生效
协程是独立栈帧,go(function () { $a = 10; }); 里的 $a 和外层不是同一个变量——这不是 Bug,是协程隔离的必然结果。
- 需要共享状态时,用
Swoole\Coroutine\Channel或Swoole\Coroutine\WaitGroup,别依赖闭包引用外部变量 - 数据库连接、Redis 实例等资源不能跨协程复用(除非明确支持协程安全),每个协程应单独创建
Swoole\Coroutine\MySQL实例 - 调试时用
Swoole\Coroutine::getCid()打印协程 ID,确认逻辑确实在预期协程中执行
Channel、一次没 close() 的协程 MySQL 连接,都可能让服务缓慢泄漏内存或卡死——这些细节不在文档首页,但在日志里藏得最深。










