swoole_process::setAffinity() 是唯一能在 PHP 层显式设置单个进程 CPU 亲和性的 Swoole 原生方法,仅对当前进程生效且须在 fork 后立即调用;swoole_cpu_affinity() 为全局函数,仅作用于调用时的当前进程,无法影响已 fork 的子进程。
直接说结论:
是唯一能在 PHP 层显式设置单个进程 CPU 亲和性的 Swoole 原生方法,但它只对当前进程生效,且必须在子进程创建后、业务逻辑开始前调用;
是全局函数,仅作用于当前 PHP 进程(包括 master 和未 fork 的 worker),无法用于已 fork 的子进程。
为什么 setAffinity() 必须在 fork 后立即调用
Linux 的 CPU 亲和性是进程级属性,继承自父进程。Swoole 的
或
进程由 master 进程
产生,此时子进程初始亲和性与 master 完全一致。如果在子进程里延迟调用
,中间可能已被调度到其他 CPU 上运行,导致缓存预热失效、上下文切换已发生——优化就白做了。
常见错误写法:
正确时机:
在
返回子进程后,第一行就调用
或在
回调最开头,甚至早于
、
等任何系统调用
若用
,必须在
内部为每个 task 单独调用(因为 task 是复用的,每次执行前需重置)
数组参数里的数字到底指物理核还是逻辑核
它指 Linux 的「逻辑 CPU 编号」,也就是
里
字段的值,不是物理核序号,也不是超线程编号。比如一台 4 核 8 线程的机器,
会从 0 到 7,
表示绑定到第 0/2/4/6 号逻辑 CPU —— 它们大概率分布在不同物理核上(避免超线程争抢同一执行单元)。
容易踩的坑:
Swoole 6.1.1
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
下载
误用物理核数做判断:
返回的是逻辑 CPU 总数(如 8),但
若全落在同一物理核的两个超线程上,性能反而下降
硬编码数组越界:传入
在 8 线程机器上会直接返回
,且触发
,但不会抛异常,容易被忽略
没校验实际可用性:某些云主机(如 AWS t3/t4g)启用了 vCPU 混合调度,
编号不连续或存在隐藏限制,建议先用
验证
setAffinity() 失败却不报错的三种情况
它返回
,但默认不抛异常,也不打日志,很多开发者以为“没生效”其实是“调用失败了”。典型场景:
进程没有权限:非 root 用户在部分发行版(如 CentOS 7+)默认禁止普通进程修改亲和性,
(
),需加
权限或改
CPU 编号超出范围:比如传
但机器只有 4 个逻辑 CPU(编号 0–3),源码里会直接
传入空数组:
立刻返回
,但这是合法调用(表示解除绑定),行为等价于
,别误判为失败
建议防御式写法:
和 taskset 命令、
swoole
_cpu_affinity() 的关系
三者底层都调用
,但作用域完全不同:
:外部命令,可随时修改任意进程,适合调试和临时压测,但无法嵌入 PHP 逻辑流
:只影响调用时刻的当前 PHP 进程,master 进程调用后,后续 fork 出的 worker 仍继承默认亲和性;它用位掩码,
= CPU 0,
= CPU 0 和 CPU 2
:必须在目标进程内调用,且只对该进程生效,是真正可控的细粒度绑定方式
关键区别在于:如果你要让 8 个 worker 分别绑在 8 个逻辑 CPU 上,
无能为力,必须用
配合
动态计算。
最后提醒一句:CPU 亲和性不是银弹。当你的瓶颈在 MySQL 连接池耗尽、Redis 阻塞调用或协程栈溢出时,绑再准的 CPU 也救不了 —— 先看
和
确认是否真卡在调度上。
swoole_process::setAffinity()swoole_cpu_affinity()workertask_workerfork()setAffinity()// ❌ 错误:在 onWorkerStart 里做耗时初始化后再绑定
$server->on('WorkerStart', function ($server, $worker_id) {
// 这里加载了大量类、连接 Redis、初始化协程池...
// 调度器可能已把该 worker 切到别的 CPU 上跑了几十毫秒
swoole_process::setAffinity([0]);
});
swoole_process::fork()setAffinity()onWorkerStartechofile_get_contents()task_workeronTask/proc/cpuinfoprocessorprocessorsetAffinity([0, 2, 4, 6])swoole_cpu_num()setAffinity([4, 5, 6, 7])[8]falseE_WARNINGprocessortaskset -c 0 -- echo okfalseerrno=1EPERMcap_sys_nice/proc/sys/kernel/sched_autogroup_enabled[0, 1, 2, 3, 4]RETURN_FALSEsetAffinity([])falsetaskset -p 0 if (!swoole_process::setAffinity([0])) {
trigger_error('setAffinity failed, check cpu id and privileges', E_USER_WARNING);
}
sched_setaffinity()taskset -cp 0 swoole_cpu_affinity(0b0001)0b00010b0101swoole_process::setAffinity([0, 2])swoole_cpu_affinity()setAffinity()$worker_id % swoole_cpu_num()swoole_server->stats()strace -p -e trace=sched_setaffinity 