4. taskset 命令详解
taskset 是 Linux 系统中用于查看和设置进程 CPU 亲和性(CPU affinity)的核心命令行工具。它允许管理员将进程绑定到指定的 CPU 核心或核心组,从而控制进程在哪些处理器上运行。在多核系统中,合理使用 taskset 可以显著减少缓存未命中、降低上下文切换开销,并提升关键应用的性能稳定性。
适用场景: taskset 适用于用户态进程的 CPU 绑定。对于内核线程或中断处理程序的绑定,应使用
irqbalance、/proc/irq/ 接口或 cpuset 子系统。
4.1 taskset 语法与参数
taskset 的基本语法格式如下:
taskset [options] mask command [argument...]
taskset [options] -p [mask] pid
常用参数说明:
| 参数 | 功能说明 | 示例 |
|---|---|---|
-p, --pid |
操作已运行的进程,而非启动新进程 | taskset -p 1234 |
-c, --cpu-list |
以 CPU 列表形式指定核心(如 0,2,4-7) | taskset -c 0,2 myapp |
-a, --all-tasks |
操作指定进程的所有线程(线程组) | taskset -ap 0 1234 |
mask |
十六进制 CPU 掩码,每位代表一个核心 | 0x01 表示 CPU 0 |
掩码与 CPU 列表的对应关系: 十六进制掩码
0x0F 对应二进制 1111,表示 CPU 0-3;0x55 对应 01010101,表示 CPU 0,2,4,6。使用 -c 参数可以更直观地指定核心编号。
4.2 查看进程当前 CPU 亲和性
查看进程的 CPU 亲和性有两种常用方式:
- 方式一: 使用
taskset -p <pid>查看指定进程的亲和性掩码。 - 方式二: 读取
/proc/<pid>/status中的Cpus_allowed字段。
示例:查看 PID 为 1234 的进程当前绑定情况:
# 使用 taskset 查看
$ taskset -p 1234
pid 1234's current affinity mask: 3
# 使用 /proc 查看
$ grep Cpus_allowed /proc/1234/status
Cpus_allowed: 03
Cpus_allowed_list: 0-1
输出说明:掩码 3(二进制 0011)表示该进程允许在 CPU 0 和 CPU 1 上运行。Cpus_allowed_list 以更直观的列表形式显示允许的核心范围。
注意: 如果进程的亲和性掩码为
f(所有核心),并不代表进程会均匀分布在所有核心上,而是表示调度器可以在任何核心上调度该进程。实际运行核心取决于调度策略和当前负载。
4.3 设置进程 CPU 亲和性
设置亲和性分为两种情况:启动新进程时绑定,或修改已运行进程的绑定。
4.3.1 启动新进程时绑定
在启动命令时直接指定 CPU 亲和性:
# 将 myapp 绑定到 CPU 0(掩码方式)
$ taskset 0x01 ./myapp
# 将 myapp 绑定到 CPU 0 和 CPU 2(CPU 列表方式)
$ taskset -c 0,2 ./myapp
# 将 myapp 绑定到 CPU 0-3(范围方式)
$ taskset -c 0-3 ./myapp
4.3.2 修改已运行进程的绑定
使用 -p 参数修改已运行进程的亲和性:
# 将 PID 为 1234 的进程绑定到 CPU 0
$ taskset -p 0x01 1234
# 将 PID 为 1234 的进程绑定到 CPU 2-3
$ taskset -pc 2,3 1234
# 将 PID 为 1234 的所有线程绑定到 CPU 0-1
$ taskset -apc 0-1 1234
实践建议: 对于多线程应用,使用
-a 参数确保所有线程都继承相同的亲和性设置。如果只设置主线程,子线程可能被调度到其他核心,导致绑定失效。
4.4 绑定到特定 CPU 核心
在实际性能优化中,常见的绑定策略包括:
| 策略 | 命令示例 | 适用场景 |
|---|---|---|
| 绑定到单个核心 | taskset -c 0 ./app |
延迟敏感型单线程应用 |
| 绑定到物理核心(避开超线程) | taskset -c 0,2,4,6 ./app |
计算密集型任务,避免超线程干扰 |
| 绑定到同一 NUMA 节点 | taskset -c 0-3 ./app |
内存访问密集型应用,减少跨 NUMA 延迟 |
| 隔离核心 + 绑定 | taskset -c 1 ./app(配合 isolcpus) |
实时任务或高优先级批处理 |
4.5 实战案例:绑定数据库进程
以下是一个完整的实战案例,展示如何将 MySQL 数据库进程绑定到指定核心:
# 1. 查找 MySQL 进程 PID
$ pgrep -x mysqld
5678
# 2. 查看当前亲和性
$ taskset -p 5678
pid 5678's current affinity mask: ff
# 3. 绑定到 CPU 0-3(前 4 个核心)
$ taskset -pc 0-3 5678
# 4. 验证绑定结果
$ taskset -p 5678
pid 5678's current affinity mask: 0f
# 5. 查看实际运行核心(使用 ps 或 top)
$ ps -o pid,psr,comm -p 5678
PID PSR COMMAND
5678 0 mysqld
验证技巧:
ps -o pid,psr,comm -p <PID> 中的 PSR 列显示进程当前正在运行的核心编号。如果绑定成功,该值应在允许的核心范围内。注意:PSR 值会随调度变化,多次查看可确认绑定是否生效。
4.6 常见问题与避坑指南
- 权限问题: 修改其他用户的进程亲和性需要 root 权限或
CAP_SYS_NICE能力。 - 掩码计算错误: 十六进制掩码从低位开始对应 CPU 0。例如
0x10(十进制 16)对应 CPU 4,而非 CPU 1。 - 超线程混淆: 在 Intel/AMD 平台上,物理核心和逻辑核心(超线程)共享 L1/L2 缓存。绑定到同一物理核心的两个逻辑核心可能导致资源争抢。
- NUMA 跨节点: 如果进程绑定到不同 NUMA 节点的核心,内存访问延迟会显著增加。使用
numactl --hardware查看节点拓扑。 - 持久化问题: taskset 设置仅在进程运行期间有效。如需持久化绑定,应在启动脚本或 systemd 单元文件中配置。
重要提醒: 过度绑定可能导致 CPU 利用率不均,部分核心过载而其他核心空闲。建议在绑定前使用
perf stat 或 mpstat 分析进程的缓存命中率、上下文切换频率和迁移次数,确认绑定确实能带来性能收益。