Swoole 没有线程池,只有进程池和协程;task_worker_num 是同步阻塞式任务进程池数量,非线程数;MySQL 连接应使用协程连接池而非进程模拟。

Swoole 没有“线程池”——只有进程池和协程,别被“线程”二字带偏
PHP 本身不支持真正意义上的多线程(ZTS 模式极少见且不推荐),Swoole 的 swoole_process 和 Swoole\ProcessPool 全部基于 多进程 实现。所谓“MySQL 线程池”“任务线程池”,实际是用进程模拟的并发单元,底层无 pthread 创建。混淆概念会导致配置错、压测崩、调试懵。
为什么不能用 swoole_thread 或 pthread?
PHP 官方早已废弃 pthread 扩展;Swoole 从 4.0+ 彻底移除所有线程相关 API(如 swoole_thread)。当前稳定版(v5.x)仅提供:
-
swoole_process:单个子进程,适合轻量异步任务(如日志写入、通知推送) -
Swoole\ProcessPool:预启固定数量工作进程,适合 CPU 密集型或需隔离内存的任务 -
task_worker_num(在swoole_server中):这是最常被误称为“线程池”的地方——它其实是**同步阻塞式任务进程池**,由 Manager 进程统一管理
task_worker_num 怎么设才不翻车?
这个参数控制的是 swoole_server 内置的 TaskWorker 进程数,不是“线程数”,也不是“MySQL 连接数”。设错会直接卡死请求或 OOM:
- 值设为
0:禁用 TaskWorker,->task()调用直接报错Task worker is not available - 值过大(如 >100):每个 TaskWorker 占用独立内存+PHP 执行环境,易触发
Fork failed: Cannot allocate memory - 值过小(如 =1):高并发下任务排队严重,
taskwait()阻塞时间飙升,Worker 被拖慢甚至超时 - 推荐公式:
min(16, max(2, (int)ceil($concurrent_requests / 5)))—— 例如你压测峰值 200 QPS,起步可设task_worker_num => 8,再根据task_queue_length监控调整
真要“池化 MySQL 连接”,别碰进程池,用协程连接池
用 Swoole\Coroutine\MySQL + Swoole\Runtime::enableCoroutine() 是现代 Swoole 的标准做法。所谓“MySQL 线程池”本质是协程级连接复用,不是靠多进程硬扛:
- 错误姿势:用
Swoole\ProcessPool启一堆进程,每个连一个 MySQL——连接数爆炸、状态难同步、事务无法跨进程 - 正确姿势:在协程内调用
new Swoole\Coroutine\MySQL,配合go并发执行,连接自动归还到协程调度器维护的隐式池中 - 关键配置:
mysql->connect()前必须确保已调用Swoole\Runtime::enableCoroutine(),否则仍是同步阻塞 - 示例片段:
Swoole\Runtime::enableCoroutine(); go(function () { $mysql = new Swoole\Coroutine\MySQL(); $mysql->connect(['host' => '127.0.0.1', 'user' => 'root']); $result = $mysql->query('SELECT sleep(1)'); var_dump($result); });
最容易被忽略的是:协程连接池不等于“连接永不释放”,close() 不是必须,但长连接空闲超时(由 MySQL server 的 wait_timeout 控制)仍会断开,框架会自动重连——这和传统连接池的保活逻辑完全不同。别在协程里手动 sleep 或长时间阻塞,那会卡住整个协程调度器。










