task_worker_num应设为worker_num×0.5~2,io密集型取下限,cpu密集型可取上限但不超过cpu核数×2;须配task_max_request、task_tmpdir等防故障参数,并通过ps和stats验证实效。

task_worker_num 该设多少,取决于 CPU 核心数和任务类型
它不是“越多越好”,而是要和 worker_num 协同控制 IPC 压力与实际吞吐。task 进程本质是独立子进程,靠管道或消息队列通信,上下文切换、序列化、队列排队都会吃资源。
常见错误现象:task_wait_queue_len 持续 > task_worker_num × 100,或 tasking_num 长期满载,说明 task 进程不够用;但若 task_worker_num 超过 worker_num × 2 后 QPS 不升反降,大概率是 IPC 开销压垮了调度器。
- IO 密集型任务(如调外部 API、发邮件、写日志):可设为
worker_num × 0.5~1,比如worker_num=16,则task_worker_num=8~16 - CPU 密集型任务(如图像处理、大 JSON 解析、RSA 加解密):建议设为
worker_num × 1~2,但上限别超swoole_cpu_num() × 2,否则容易触发Fork failed: Resource temporarily unavailable - 单机内存 ≤ 4GB 时,
task_worker_num别超过 16 —— 每个 task 进程也占 10~30MB 内存,叠加worker_num容易 OOM
必须配的配套参数,漏一个就可能丢任务
task_worker_num 单独设了没用,Swoole 启动时会直接报错,除非你同时注册了 onTask 和 onFinish 回调。更关键的是,不设下面这几个,生产环境迟早出事:
-
task_max_request:必须设,推荐500~2000,防内存泄漏导致 task 进程越跑越慢甚至卡死 -
task_tmpdir:必须指向可写的 tmpfs(如/dev/shm),否则 msgqueue 模式下投递失败静默丢任务 -
task_enable_coroutine:默认 false,如果 task 里要用协程(比如异步 Redis),得显式设为true,否则co::sleep()会阻塞整个 task 进程
怎么验证 task 配置真生效了?别信配置文件
改完 task_worker_num 后,光看 config 文件或 reload 日志没用。系统级工具拦截、supervisor 未透传信号、PHP 进程残留都可能导致实际进程数不对。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
实操建议:
- 启动后立刻执行:
ps aux | grep "php.*server" | grep -v grep,确认 task 进程数 = 你设的值 +worker_num+ 1 个 master 进程 - 运行中查实时状态:
$server->stats()返回数组里看task_worker_num、tasking_num、task_wait_queue_len三个字段 - 压测时盯住
task_wait_queue_len的 P95 延迟,持续 > 500ms 就说明 task 处理不过来,得加task_worker_num或优化 onTask 逻辑
为什么 8 核机器 task_worker_num 设 32 反而更慢?
因为 task 进程间没有共享内存,每次投递都要序列化数据、走 IPC、反序列化,task_worker_num > swoole_cpu_num() × 2 后,内核调度抖动明显上升,top 里能看到大量 sy(system)CPU 占用飙升。这不是业务慢,是操作系统在疲于切换进程上下文。
真实瓶颈往往不在 task 数量,而在 onTask 里写了阻塞操作(比如没加超时的 cURL、同步 file_get_contents)——这种情况下加再多 task 进程也没用,只会让队列积压更严重。
复杂点在于:task 进程的生命周期和 worker 完全隔离,static、global、对象实例都不共享,连 opcache 都是各自一份。你以为投了个任务过去能复用连接池?其实每次都是新进程、新连接、新初始化。这点很容易被忽略。










