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(所有核心),并不代表进程会均匀分布在所有核心上,而是表示调度器可以在任何核心上调度该进程。实际运行核心取决于调度策略和当前负载。
查看进程 CPU 亲和性流程 获取进程 PID 方式一:taskset -p <PID> 方式二:/proc/<PID>/status 输出:affinity mask: 3 输出:Cpus_allowed: 03 掩码 3 = 二进制 0011 → 允许 CPU 0 和 CPU 1

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) 实时任务或高优先级批处理
taskset 绑定策略示意图 物理 CPU 核心布局(8 核系统示例) CPU 0 CPU 1 CPU 2 CPU 3 CPU 4 CPU 5 CPU 6 CPU 7 策略 1 绑定到单个核心 taskset -c 0 ./app 策略 2 绑定物理核心(避开超线程) taskset -c 0,2,4,6 ./app 策略 3 绑定到同一 NUMA 节点 taskset -c 0-3 ./app 策略 4 隔离核心 + 绑定 isolcpus=1 + taskset -c 1 ./app NUMA Node 0 NUMA Node 1

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 分析进程的缓存命中率、上下文切换频率和迁移次数,确认绑定确实能带来性能收益。