per-task affinity 是什么?
Per-Task Affinity(任务级CPU亲和性)详解
Per-Task Affinity 是 Linux 调度器提供的一种机制,允许将单个任务(进程/线程)绑定到特定的 CPU 核心(或核心集合)上运行,从而优化性能、减少缓存失效或实现资源隔离。
1. 核心概念
(1) 基本作用
- 控制任务运行位置:强制任务只在指定的 CPU 核心上执行,避免被调度到其他核心。
- 减少迁移开销:避免跨核心迁移导致的 缓存失效(Cache Miss) 和 TLB 刷新,提升计算密集型任务的性能。
- 隔离干扰:防止高优先级任务抢占关键核心,或确保低延迟任务独占 CPU。
(2) 实现方式
-
cpu_allowed
掩码(bitmask):
每个任务(task_struct
)有一个cpus_allowed
位图,标记允许运行的 CPU 核心。
例如:0x1
(二进制0001
):仅允许在 CPU 0 运行。0x7
(二进制0111
):允许在 CPU 0、1、2 运行。
-
调度器行为:
在select_task_rq()
选择运行队列时,调度器会检查cpus_allowed
,确保任务只在合法 CPU 上运行。
2. 配置方法
(1) 命令行工具 taskset
# 启动新任务并绑定到 CPU 0 和 1
taskset -c 0,1 ./my_program# 修改已运行任务的亲和性(PID=1234 → 绑定到 CPU 2)
taskset -cp 2 1234# 查看任务的当前亲和性
taskset -p 1234
输出示例:
pid 1234's current affinity mask: 4 # 4 = 0b100(仅允许 CPU 2)
(2) 编程接口 sched_setaffinity()
#define _GNU_SOURCE
#include <sched.h>cpu_set_t set;
CPU_ZERO(&set); // 清空掩码
CPU_SET(0, &set); // 允许 CPU 0
CPU_SET(2, &set); // 允许 CPU 2// 设置当前任务的亲和性
if (sched_setaffinity(0, sizeof(set), &set) == -1) {perror("sched_setaffinity failed");
}
3. 使用场景
(1) 高性能计算(HPC)
- 绑定计算线程到独立核心,避免上下文切换和缓存抖动。
# 让矩阵乘法任务独占 CPU 3 taskset -c 3 ./matrix_multiply
(2) 实时任务(Low-Latency)
- 确保关键任务(如网络包处理)不被迁移,减少延迟波动。
// 实时线程绑定到 CPU 5 CPU_SET(5, &set); sched_setaffinity(0, sizeof(set), &set);
(3) 干扰隔离
- 防止 noisy neighbor(嘈杂邻居)问题:
将数据库进程绑定到一组核心,避免其他任务抢占资源。# MySQL 仅使用 CPU 4-7 taskset -c 4-7 /usr/sbin/mysqld
4. 与 CGroup cpuset
的关系
特性 | Per-Task Affinity | CGroup cpuset |
---|---|---|
作用范围 | 单个任务 | 一组任务(整个 cgroup) |
优先级 | 必须服从 cpuset 约束 | 全局限制(可覆盖 affinity) |
灵活性 | 允许动态调整 | 需修改 cgroup 配置 |
典型用途 | 精细化调优(如绑定线程) | 资源隔离(如容器、虚拟机) |
关键规则:
任务的最终可用 CPU = cpuset.cpus ∩ task_affinity
(交集)。
- 如果
cpuset
只允许 CPU 0-3,而affinity
设为 CPU 2-5 → 实际可用 CPU 2-3。 - 如果
affinity
完全超出cpuset
范围(如cpuset=0-1
,affinity=2
),则任务无法运行(返回-EINVAL
)。
5. 底层实现
(1) 内核数据结构
task_struct->cpus_allowed
:存储任务的 CPU 亲和性掩码。struct rq
:每个 CPU 核心维护一个运行队列,调度器只从cpus_allowed
允许的队列中选择任务。
(2) 调度逻辑
- 在
select_task_rq()
中,内核会调用cpumask_intersects()
检查候选 CPU 是否在cpus_allowed
内。 - 如果任务尝试迁移到非法 CPU,会被强制重新调度到合法核心。
6. 注意事项
- 不要过度绑定:
- 如果绑定的 CPU 已满负载,任务可能因无法迁移而饥饿。
- NUMA 感知:
- 在 NUMA 系统中,跨节点绑定可能导致内存访问延迟升高(建议配合
numactl
使用)。
- 在 NUMA 系统中,跨节点绑定可能导致内存访问延迟升高(建议配合
- 实时性任务:
- 对于
SCHED_FIFO
/SCHED_RT
任务,需同时设置优先级和亲和性。
- 对于
总结
Per-Task Affinity 是 Linux 调度器提供的细粒度 CPU 控制机制,适用于:
- 优化计算密集型任务(减少缓存失效)
- 保障实时任务低延迟(避免迁移)
- 隔离关键负载(防止干扰)
但需注意与 cpuset
的协作关系,避免配置冲突。