CPU 亲和力(CPU affinity)是指将一个进程或线程限制在特定的 CPU 核心上运行的能力。 CPU 亲和力可以用来指定一个进程或线程在多核系统中使用哪些 CPU 核心来执行其任务。 这种技术可以优化系统性能、减少竞争,并帮助避免缓存伪共享等问题。

 

CPU 亲和力(CPU affinity)完整解构

CPU 亲和力(CPU 亲和性 / 处理器亲和掩码) 定义:操作系统调度器约束线程只能在指定的一个或多个逻辑 CPU 核心上运行,线程不会被调度到掩码以外的 CPU;分为进程级亲和线程级亲和系统级 / 中断亲和;Windows、Linux 均原生支持。 Windows 对应 API:SetProcessAffinityMask / SetThreadAffinityMask;Linux:sched_setaffinity

一、底层原理

1. 内核核心机制

现代 OS 内核调度器(Scheduler)维护每一个可运行线程的调度实体(TCB/ETHREAD),内部保存亲和掩码(Affinity Mask,位图)

  • 掩码每一位对应一个逻辑 CPU 核心:bit N =1 → 允许在 CPU N 运行;bit N=0 → 禁止调度到 CPU N
  • 调度器在做上下文切换、选核运行时,只会从掩码标记允许的 CPU 集合里挑选空闲核心
  • 软亲和 vs 硬亲和
    • 硬亲和(我们常说的 CPU affinity):强制限制只能在指定核心运行,调度器严格遵守
    • 软亲和(sched prefer):优先在之前运行过的核心(利用 CPU 缓存热度),不强制约束

补充:NUMA 架构额外配套 NUMA 节点亲和,优先分配本节点内存,减少跨 NUMA 内存访问延迟,和 CPU 亲和经常配合使用

2. Windows 内核侧关键结构

ETHREAD(内核线程块)内成员:

  • Affinity:线程亲和掩码
  • SystemAffinity:系统默认亲和
  • IdealProcessor:首选核心(理想处理器,优先调度到此核,不强制) EPROCESS(进程块):ProcessAffinityMask,进程全局默认亲和,新建线程会继承进程亲和,线程可单独覆盖

3. Linux 内核侧关键结构

task_struct

  • cpumask_t cpus_allowed:硬亲和掩码
  • cpumask_t cpus_allowed_pinned 调度器在select_task_rq选核函数中校验cpus_allowed

二、依赖文件 & 内核组件

Windows

  1. 内核主体ntoskrnl.exe(调度器核心、ETHREAD/EPROCESS 管理)
  2. 内核模块:ci.dllhal.dll(硬件抽象层 HAL,负责 CPU 拓扑、逻辑核心编号上报)
  3. 用户态 API 导出:kernel32.dll / kernelbase.dll(封装SetProcessAffinityMask等 Win32 API)
  4. 配套工具程序:taskmgr.exewmic.exepowershellstart.exe

Linux

  1. 内核核心:kernel/sched/ 调度源码,cpumask 核心库
  2. 系统调用入口:sys_sched_setaffinity
  3. 用户态工具依赖 libc:shturl.(封装sched_setaffinity
  4. 工具:tasksetnumactl

三、依赖关系

✅ 前置依赖

  1. CPU 硬件:多逻辑核心(单核 CPU 设置亲和无意义);操作系统识别正确 CPU 拓扑(HAL/ACPI 上报核心编号正常)
  2. 权限约束
    • Windows:默认普通用户只能修改自身进程亲和;修改系统进程、服务进程亲和需要SeIncreaseBasePriorityPrivilege 高权限
    • Linux:普通用户可修改自己进程;root 可修改任意进程
  3. 调度器未被第三方内核模块 / 实时补丁接管(如某些工控实时内核替换调度器,亲和逻辑可能改动)
  4. NUMA 场景:内核正确识别 NUMA 节点拓扑

✅ 后置生效链路

设置亲和掩码 → 内核更新 ETHREAD/task_struct 内 cpumask → 下一次线程调度选核时生效

⚠️ 不会立刻迁移正在运行的线程:线程当前已经跑在非允许核心上时,不会直接踢走;等到下一次时间片结束、重新调度时才会约束到合法核心

四、完整逻辑链路(Windows 示例)

示例:PowerShell 设置进程 CPU 亲和

$proc = Get-Process notepad
$proc.ProcessorAffinity = 0x03

链路拆解:

PowerShell → kernelbase.dll → NtSetInformationProcess 系统调用 → ntoskrnl 内核接收请求 → 写入EPROCESS.ProcessAffinityMask → 该进程新线程继承掩码;已有线程后续调度时校验掩码 → 调度器只在bit0、bit1核心调度该进程所有线程

Linux taskset 示例

taskset 0x03 ./app
taskset → libc → sys_sched_setaffinity → 内核task_struct.cpus_allowed更新 → 调度器选核约束

五、配套链

组件 / 工具 作用 和 CPU 亲和的关系
IdealProcessor(理想核心) 优先核心,不强制 Windows 配套,常和亲和一起配置
NUMA 节点亲和 内存分配约束 高性能场景组合使用(CPU 亲和 + NUMA 亲和)
中断亲和(IRQ Affinity) 约束硬件中断跑在指定核心 网卡、存储高性能调优,独立于进程线程亲和
TaskMgr 任务管理器 GUI 设置进程亲和 底层调用同一套 Win32 API
wmic / powershell 命令行批量设置亲和 运维自动化
numactl(Linux) 同时控制 CPU+NUMA 内存亲和 服务器性能调优核心工具
ISR/DPC(Windows) 延迟过程调用 DPC/ISR 也可单独设置 CPU 亲和

六、边界、限制、高频坑点

  1. 亲和只是调度约束,不是独占 只是限制线程能跑哪些核,不独占核心;其他进程依然可以调度到这些核心。要实现核心独占,需要配合CPU 隔离(isolcpus Linux / 核心预留 Windows)
  2. ❗ 掩码不能超出系统有效逻辑 CPU 总数 比如主机总共 4 核(0~3),掩码设置 0x10(bit4)直接报错
  3. 进程亲和是新建线程默认值,线程可单独覆盖 进程设置完亲和后,子线程可以调用SetThreadAffinityMask单独使用不同掩码
  4. ❗ Windows 部分系统进程、内核线程不允许修改亲和(受内核保护)
  5. ❗ 热插拔 CPU 场景:CPU 离线后,原有亲和掩码如果包含离线核心,行为由系统版本决定(新版自动屏蔽失效 bit)
  6. ❗ 超线程 SMT 场景:逻辑核是独立编号,亲和可以单独绑定单个逻辑核
  7. 不具备实时性:普通 CFS/Windows 调度器只是遵守掩码,不能保证确定性延迟;工业实时场景需要 RTOS / 实时内核
  8. ❗ 虚拟机内 CPU 亲和:宿主机 vCPU 亲和 和 客户机内 CPU 亲和是两层独立控制,极易混淆
  9. ❗ 休眠 / 快速启动场景,亲和配置不持久,进程重启后亲和恢复默认

七、常用实操命令速记

Windows

# 查询进程亲和
Get-Process notepad | Select-Object Name,Id,ProcessorAffinity

# 设置亲和 仅允许在核心0、1运行(0x03)
$p = Get-Process notepad
$p.ProcessorAffinity = 0x03

# 启动程序并直接指定亲和
start /affinity 3 notepad.exe

Linux

# 绑定已有进程pid 只在核心0,1运行
taskset -p 0x03 1234

# 启动程序直接绑定核心0,1
taskset 0x03 ./app

# 同时控制NUMA+CPU亲和
numactl --cpunodebind=0 --membind=0 ./app

CPU 亲和力(CPU affinity)应用场景

前置核心前提:CPU 亲和本质是调度约束,不是核心独占;想要完全隔离核心,需要额外做 CPU 隔离(isolcpus、预留核心);常和中断亲和、NUMA 亲和配套落地。

一、低延迟 / 实时业务场景(最核心)

  1. 工控实时程序、运动控制、PLC 配套软件 业务线程绑定固定核心,减少跨核迁移带来的缓存失效、上下文切换抖动,保证调度确定性;工业设备、机器视觉采集、数据采集程序高频使用。
  2. 高频交易、行情接收、低延迟网关 收包 / 处理线程固定在指定核心,避免系统其他进程、内核线程频繁抢占;一般配套网卡 IRQ 亲和绑定同一组核心。
  3. 音视频实时编码 / 推流 编码线程绑定专属核心,防止突发调度抖动导致帧丢包、音画卡顿。

二、服务器高性能业务优化(数据库、缓存)

  1. MySQL、PostgreSQL、Redis、Elasticsearch 大内存数据库 / 缓存跑在 NUMA 服务器上,CPU 亲和 + NUMA 内存亲和组合,线程固定节点内核心,内存优先分配本地节点内存,规避跨 NUMA 访问延迟。
  2. 消息队列(Kafka、RocketMQ) IO 线程、网络线程单独绑核,隔离业务计算线程,避免 IO 中断和业务争抢核心。
  3. 高性能计算 HPC、仿真、渲染 并行计算任务绑定一组核心,减少线程迁移,提升 L1/L2 缓存命中率。

三、虚拟化 & 容器场景

  1. 宿主机 vCPU 绑核 KVM/VMware,把虚拟机 vCPU 固定到宿主机物理核心,避免不同虚拟机 vCPU 互相抢占,提升虚拟机稳定性;云主机、隔离租户场景常用。
  2. 容器(Docker/K8s)CPU 绑核 --cpuset-cpus,限定容器内进程只能跑指定核心,实现资源硬隔离,避免业务之间相互干扰。
  3. 直通设备虚拟机(GPU / 网卡直通) vCPU + 设备中断绑定同一核心,降低直通设备 IO 延迟。

四、多实例服务隔离场景

  1. 多实例网关、多进程采集程序 多个独立业务进程分别绑定不同核心,实现资源物理隔离,防止某一个实例 CPU 打满拖垮其他业务。
  2. 压测工具、性能测试 压测进程单独绑核,精准控制压测算力,避免系统其他进程干扰性能指标采集,保证测试数据可信。

五、系统内核、驱动调优场景

  1. DPDK、VPP 高性能数据面 DPDK 轮询线程(PMD 线程)强制绑核,同时关闭 irqbalance、中断亲和对齐 PMD 核心,是标准落地方案。
  2. 存储高性能服务(iSCSI、NVMe 存储网关) 存储 IO 处理线程绑定核心,配合 NVMe 队列中断亲和,降低 IO 时延。

六、兼容 / 缺陷规避场景

  1. 老旧闭源软件、单线程老程序 部分老旧软件多核心下存在 bug、逻辑异常,强制限制仅在单个核心运行保证稳定性。
  2. 特定硬件兼容性问题 部分外设驱动、加密卡程序在多核心调度时偶发异常,绑核规避异常。

七、不适合使用 CPU 亲和的场景(避坑)

  1. 通用 Web 服务、普通业务后台:流量波动大,绑核容易出现核心负载不均衡,操作系统自动调度效果更好
  2. 负载波动极大的弹性业务:固定核心会造成资源浪费或者瓶颈
  3. 单核轻量小程序:无收益,增加运维复杂度

配套落地标准组合清单

低延迟高性能标准方案:

CPU 亲和(业务线程) + IRQ/DPC 中断亲和(网卡 / 存储) + NUMA 节点亲和(内存分配) + 隔离核心(可选,彻底排除系统抢占)

CPU 亲和 vs 中断亲和 vs NUMA 亲和 对照表

对比项 CPU 亲和(进程 / 线程亲和 Processor Affinity) 中断亲和(IRQ Affinity / Interrupt Affinity) NUMA 亲和(NUMA Node Affinity)
管控对象 用户态 / 内核态线程、进程 硬件 ** 中断(IRQ/MSI/MSI-X)、DPC 内存分配 + CPU 调度(NUMA 节点维度)
核心作用 约束线程只能在指定逻辑 CPU 核心上被调度运行 约束硬件产生的中断信号只投递到指定逻辑核心处理 优先从指定 NUMA 节点分配内存,优先在本节点 CPU 执行,降低跨节点内存延迟
控制层级 进程 / 线程调度层(OS 调度器) 硬件中断分发层(APIC/IOMMU、内核中断管理器) 内存管理 + 调度协同层
核心数据载体 ETHREAD/EPROCESS(Windows)task_struct.cpus_allowed(Linux) 中断描述符、IRQ 掩码、MSI 目标 CPU 配置 task_struct 的 numa_mems_allowed、mempolicy、VMA 内存策略
典型使用场景 1. 工控程序绑定固定核心,减少上下文切换2. 隔离业务进程,避免抢占3. 虚拟机内部业务核绑定 1. 网卡、SSD 高性能调优,中断与业务核绑定2. 避免中断频繁抢占业务线程3. 多队列网卡 RSS 配套调优 1. 数据库、缓存、高性能计算2. 大型内存密集型服务3. 服务器 NUMA 架构性能优化
Windows 配套 API / 工具 SetProcessAffinityMask/SetThreadAffinityMask任务管理器、PowerShell ProcessorAffinitystart /affinity SetInterruptAffinity、WMI、注册表 IRQ 掩码设备管理器、bcd 全局中断配置 SetProcessPreferredNumaNodeGetNumaHighestNodeNumberPowerShell NUMA 相关接口
Linux 配套 API / 工具 sched_setaffinitytaskset /proc/irq/[num]/smp_affinityirqbalance set_mempolicynumactlnumastat
生效范围 仅约束软件线程调度,不影响硬件中断、内核 DPC(默认) 仅约束硬件中断投递,不约束普通业务线程 同时影响内存分配位置和调度节点偏好
是否独占核心 ❌ 只是调度约束,核心可被其他线程 / 中断抢占 ❌ 仅约束中断投递目标,核心可被进程抢占 ❌ 优先策略,非强制独占,可跨节点分配内存
持久特性 进程重启失效,运行时临时生效 默认临时生效;部分可写入注册表 / 内核参数持久化 进程重启失效,可配置进程默认 NUMA 策略
关键独立边界 无法限制硬件中断跑到绑定核上,容易出现 “线程绑核但中断抢占该核” 的性能坑 只管硬件中断,业务线程依然会随机跑在其他核心,需要配合 CPU 亲和一起使用 不精细控制单 CPU 核心,是以NUMA 节点(一组 CPU + 本地内存)为单位,节点内核心仍可自由调度
典型组合方案 ✅ 高性能服务器标准组合:CPU 亲和 + 中断亲和 + NUMA 亲和业务线程绑定节点内 CPU → 网卡 / 存储中断绑定同组 CPU → 内存优先分配本节点本地内存,消除跨 NUMA 访问开销    

补充关键术语精简说明

  1. DPC 亲和:属于广义中断体系(延迟过程调用),和 IRQ 亲和配套,Windows 高频调优项;
  2. IdealProcessor(理想处理器):Windows 专属,是软偏好,不属于严格 CPU 硬亲和;
  3. irqbalance:Linux 守护进程,自动均衡中断,高性能场景一般手动关闭,手动固化中断亲和;
  4. 虚拟机场景分层:宿主机 vCPU 亲和、宿主机中断亲和、客户机内 CPU/NUMA 亲和,三层相互独立,极易混淆。

高频踩坑汇总

  1. 只配置 CPU 亲和,不配置中断亲和:业务线程绑定核心后,大量网卡中断持续抢占该核心,性能反而下降;
  2. NUMA 机器只绑 CPU 不设置 NUMA 内存策略:线程跑在节点 0 的 CPU,但内存分配到节点 1,跨节点访问延迟极高;
  3. 超线程 SMT 场景:亲和掩码绑定逻辑核,中断也需要对应绑定同逻辑核,不能只看物理核编号。

 


CPU 亲和力(CPU affinity)是指将一个进程或线程限制在特定的 CPU 核心上运行的能力。

CPU 亲和力可以用来指定一个进程或线程在多核系统中使用哪些 CPU 核心来执行其任务。

这种技术可以优化系统性能、减少竞争,并帮助避免缓存伪共享等问题。

CPU 亲和性在处理缓存伪共享等问题上可以发挥重要作用:

  1. 缓存效果:在多核系统中,不同核心的缓存是相互独立的,当多个线程同时访问同一块数据时,可能导致数据在不同核心的缓存之间被频繁地传输,这就是缓存伪共享。通过设置 CPU 亲和性,可以将相关的线程绑定到同一个或相邻的核心上,减少了数据在不同核心之间的传输,降低了缓存伪共享的影响,提高了缓存的命中率和程序的性能。

  2. 资源竞争:缓存伪共享会增加不必要的内存访问和数据传输,导致多个核心之间的资源竞争,影响了系统的性能。通过设置 CPU 亲和性,可以将相关的线程绑定到同一组或同一个核心上,减少了对共享数据的竞争,降低了资源争用,提高了系统的整体性能。

  3. NUMA 效应:在 NUMA 架构中,每个内存节点与特定的 CPU 核心相关联,跨节点访问内存会引入额外的延迟和带宽消耗。缓存伪共享会导致跨节点的内存访问增多,进一步加剧了 NUMA 效应的影响。通过设置 CPU 亲和性,可以将相关的线程绑定到同一个 NUMA 节点上的核心上,减少了跨节点的内存访问,降低了 NUMA 效应的影响,提高了内存访问的效率。

CPU affinity(CPU 亲和性)是指将进程或线程与特定的 CPU 核心进行绑定,使其在执行过程中只在指定的核心上运行。它可以解决以下一些问题:

  1. 缓存效果:CPU 有多级缓存,而每个核心都有自己的缓存。当进程或线程频繁地在多个核心间切换执行时,会导致缓存的失效,从而降低了缓存的命中率,影响了程序的性能。通过设置 CPU 亲和性,可以将进程或线程绑定到特定的核心上,增加了缓存的命中率,提高了程序的执行效率。

  2. 资源竞争:在多核系统中,多个进程或线程同时运行时可能会共享某些资源,如内存、缓存、总线等。如果这些进程或线程频繁地在不同核心间切换执行,就会增加资源的竞争和争用,导致性能下降。通过设置 CPU 亲和性,可以减少进程或线程之间的资源竞争,提高系统的整体性能。

  3. 负载均衡:在一个系统中,不同的应用程序或任务可能有不同的计算量和优先级。通过设置 CPU 亲和性,可以将计算密集型的任务绑定到一个或多个特定的核心上,将高优先级的任务分配给更强大的核心,实现负载均衡和性能优化。

  4. 实时性:对于一些实时应用程序,如音视频处理、数据采集等,对响应时间要求较高。通过设置 CPU 亲和性,可以确保这些实时任务在指定的核心上独占运行,避免被其他任务的干扰,提高系统的实时性能。

  5. 可预测性:在一些对延迟敏感的应用中,如高频交易系统、游戏引擎等,需要保证系统的响应时间可预测。通过设置 CPU 亲和性,可以减少进程或线程切换的开销,提高系统的可预测性和稳定性。

  6. 避免 NUMA 效应:在 NUMA(Non-Uniform Memory Access)架构的系统中,不同的 CPU 核心访问内存的延迟和带宽可能不同。通过设置 CPU 亲和性,可以将进程或线程与距离其内存节点更近的 CPU 核心绑定,减少 NUMA 效应对性能造成的影响,提高内存访问效率。

  7. 减少上下文切换:在多核系统中,如果进程或线程频繁地在不同核心间切换执行,会增加上下文切换的开销,降低系统的性能。通过设置 CPU 亲和性,可以减少核心间的任务切换,减少上下文切换的次数,提高系统的效率。

  8. 节能和热管理:在移动设备或数据中心等对能耗和散热有一定要求的场景中,通过设置 CPU 亲和性,可以将任务集中在少数核心上运行,让其他核心处于休眠或低功耗状态,从而实现节能和热管理的效果。

  9. 提高可靠性:通过设置 CPU 亲和性,可以降低系统中不必要的干扰和竞争,提高系统的稳定性和可靠性。特别是在一些对系统稳定性要求较高的场景中,合理设置 CPU 亲和性可以有效减少意外情况的发生,提升系统的可靠性。

  10.  

为什么需要 CPU 亲和力?

  1. 性能优化:通过将特定进程绑定到特定的 CPU 核心上,可以避免在不同核心之间频繁切换,提高缓存命中率,从而提升性能。
  2. 避免竞争:在多核系统中,不同进程、线程对 CPU 核心的竞争可能导致性能下降。通过设置 CPU 亲和力,可以避免这种竞争。
  3. 确保实时性:对于需要实时性的任务,可以通过 CPU 亲和力确保任务能够在指定的 CPU 核心上及时执行,避免被其他任务干扰。

如何设置 CPU 亲和力?

  1. 操作系统支持:首先,操作系统必须支持 CPU 亲和力设置,比如 Linux、Windows 等主流操作系统一般都支持这一功能。
  2. 工具或接口:通常可以通过操作系统提供的工具或接口来设置 CPU 亲和力,比如 Linux 下的 taskset 命令。
  3. 编程接口:对于程序员而言,也可以通过编程接口(如 POSIX 线程库提供的函数)来设置线程的 CPU 亲和力。

CPU亲和力(CPU affinity)是指将一个或多个进程或线程绑定到特定的CPU核心或处理器上运行的能力。它可以通过操作系统提供的API或工具来实现。

CPU亲和力的作用如下:

  1. 优化性能:通过将进程或线程与特定的CPU核心绑定,可以减少在不同核心之间的频繁切换,从而降低了缓存失效、上下文切换等带来的开销,提高了系统的整体性能。

  2. 控制资源分配:通过设置CPU亲和力,可以控制特定进程或线程使用的CPU资源,以便更好地分配系统资源,提高整体的系统可用性和吞吐量。

  3. 减少干扰:将关键任务或实时任务绑定到特定的CPU核心,可以避免其他任务对其产生干扰,提高任务的响应性和实时性。

  4. 节能和降温:通过合理设置CPU亲和力,可以选择性地关闭或休眠未使用的CPU核心,从而减少功耗和降低温度,延长电池寿命等。

然而,不正确或滥用CPU亲和力可能带来以下影响:

  1. 负载不均衡:如果某些CPU核心被过度绑定,而其他核心空闲,可能导致负载不均衡,使得系统无法充分利用所有的处理能力。

  2. 资源竞争:当多个进程或线程被绑定到同一个CPU核心时,它们可能会发生资源竞争,导致性能下降或不稳定。

  3. 硬件局限:某些特殊的处理器架构或操作系统可能对CPU亲和力的支持有限,可能无法完全实现预期的效果。


在 Windows 系统中:

  1. 查看当前CPU亲和力设置:

    • 在任务管理器中可以查看每个进程所在的CPU核心。
      • 打开任务管理器(Ctrl + Shift + Esc)。
      • 在“详细信息”选项卡中,右键单击列标题,选择“选择列”。
      • 勾选“CPU 亲和性”列,即可查看每个进程的CPU亲和力设置。

在 Windows 系统中:

  1. 打开 PowerShell 命令行,输入以下命令来获取 CPU 的详细信息:

    bashCopy Code
    Get-WmiObject -Class Win32_Processor | Select-Object -Property *
  2. 在输出结果中查找与CPU特性相关的信息,寻找是否有关于亲和力设置的支持信息。


Get-WmiObject -Class Win32_Processor 完整解构

命令:Get-WmiObject -Class Win32_Processor | Select-Object -Property * 补充说明:Get-WmiObject 是旧 WMI 接口,新版推荐 Get-CimInstance Win32_ProcessorWin32_Processor 类本身只用于读取 CPU 硬件 / 能力属性,不能直接设置 CPU 亲和,亲和属于进程 / 线程属性,不在此类

一、底层原理

  1. 基础架构 Get-WmiObject → WMI 服务(winmgmt.exe)→ WMI 提供程序 CIMWin32.dll → 读取系统内核、HAL、注册表、CPUID 信息,组装成 Win32_Processor WMI 实例返回。 Win32_Processor只读硬件描述类,描述物理 CPU / 逻辑处理器的硬件能力、拓扑、支持特性;不存储、不管理运行时 CPU 亲和配置

CPU 亲和是进程 / 线程的运行时调度属性,对应 WMI 类是 Win32_ProcessProcessAffinityMask 属性),不是 Win32_Processor

  1. Win32_Processor 中和亲和 / 调度 / 多核能力强相关的核心字段

    属性 含义 和 CPU 亲和的关联
    NumberOfLogicalProcessors 单物理 CPU 内逻辑核心总数 决定亲和掩码有效 bit 上限,掩码不能超过该数值对应的最大逻辑核编号
    NumberOfCores 单物理 CPU 内物理核心数量 绑核、NUMA 资源规划时区分物理核 / 超线程逻辑核,指导合理分配业务
    MaxClockSpeed 处理器最大主频(MHz) 仅作为性能基线参考,和 CPU 亲和机制本身无关
    ProcessorType 处理器类型标识(比如主处理器) 仅硬件分类标记,不直接参与亲和、调度逻辑
    SocketDesignation CPU 插槽编号,如 Socket 0、Socket 1 多 CPU 服务器场景,用于区分不同插槽 CPU,配合 NUMA 节点做跨插槽绑核规划
    Family / Model / Stepping CPU 系列、型号、步进信息 用来判定 CPU 硬件能力,判断是否支持 APIC、MSI、SMT 等,是中断亲和、多核调度的硬件前提
    FeatureSet CPU 特性位图,编码 HT、APIC 等硬件能力 标识硬件是否支持多核中断分发、多核心调度,是配置 IRQ 中断亲和的底层硬件判定依据
    NumaNode 当前 CPU 归属的 NUMA 节点编号 NUMA 亲和规划核心字段,用于同节点内 CPU + 内存绑定,规避跨 NUMA 访问延迟

    补充备注

    1. Win32_Processor全部为硬件静态能力字段不存储任何进程 / 线程实时亲和配置;进程亲和掩码读取 / 修改使用Win32_Process.ProcessAffinityMask
    2. 虚拟机环境下,该类读取到的是虚拟化暴露的 vCPU 拓扑,不是物理主机真实 CPU 信息
    3. 部分老旧系统、精简系统中SocketDesignationNumaNode可能为空,无法正常采集 NUMA 拓扑

⚠️ 重点边界:Win32_Processor 没有任何字段可以读取 / 修改当前正在运行进程的 CPU 亲和值。 ✅ 进程亲和掩码读取要使用:Get-WmiObject Win32_Process | Select-Object Name,ProcessId,ProcessAffinityMask

  1. 数据来源
  • CPU 基础拓扑、核心数量:hal.dll + ACPI、CPUID 指令
  • NUMA 节点信息:内核内存管理器、ntoskrnl.exe
  • FeatureSet 等能力位:直接执行 CPUID 指令采集

二、依赖文件

  1. 主程序:Get-WmiObject 属于 System.Management(.NET),PowerShell 内置
  2. WMI 核心组件
    • winmgmt.exe:WMI 服务进程
    • CIMWin32.dll:Win32 信息 WMI 提供程序(核心
    • wbemprox.dllwbemsvc.dll:WMI COM 代理
  3. 内核 & 硬件抽象层
    • ntoskrnl.exe:内核,CPU 拓扑、NUMA 信息
    • hal.dll:硬件抽象层,CPUID、APIC、多核心拓扑上报
  4. .NET 程序集:System.Management.dll(Get-WmiObject 底层依赖)

新版 CIM(Get-CimInstance)依赖:wsman.dllcimprov.dll,不再强依赖传统 WMI

三、依赖关系

✅ 前置依赖

  1. winmgmt WMI 服务正常运行(sc query winmgmt
  2. 系统能够正常读取 ACPI 表、CPUID 指令;虚拟机内需要虚拟机暴露 CPU 拓扑信息
  3. 权限:普通用户即可读取 Win32_Processor 硬件信息,不需要管理员
  4. 无内核级过滤驱动拦截 WMI 查询

✅ 后置链路

查询得到的 NumberOfLogicalProcessors / NumaNode / SocketDesignation → 用于计算合法 CPU 亲和掩码、规划绑核方案、中断亲和分配

数据流:硬件 CPU 能力数据 → Win32_Processor → 运维人员据此设置 Win32_Process 的 ProcessAffinityMask

四、完整逻辑链路

PowerShell 执行 Get-WmiObject Win32_Processor
↓
System.Management.dll 调用WMI COM接口
↓
winmgmt.exe 接收查询请求 → 调用 CIMWin32.dll 提供程序
↓
CIMWin32.dll 调用HAL/内核接口,执行CPUID、读取ACPI、读取NUMA拓扑
↓
组装Win32_Processor实例属性(NumberOfLogicalProcessors、NumaNode、FeatureSet等)
↓
数据返回PowerShell,输出全部属性

如果要读取进程实际亲和,链路需要切换到 Win32_Process.ProcessAffinityMask

Get-WmiObject Win32_Process | Select Name,ProcessId,ProcessAffinityMask

五、配套链

组件 / 命令 作用 和本条命令的配套关系
Get-WmiObject Win32_Process 读取 / 修改进程ProcessAffinityMask 本命令获取 CPU 核心拓扑后,用此类设置亲和
Get-CimInstance Win32_Processor CIM 新版等价替代 推荐替代 Get-WmiObject
Get-CimInstance Win32_Process CIM 读取进程亲和 现代化运维标准
wmic cpu get NumberOfLogicalProcessors,NumaNode CMD 等价查询 批处理环境使用
wmic process set ProcessAffinityMask CMD 设置进程亲和 配套绑核落地
bcdedit /set numaprocs 全局 NUMA/CPU 调度配置 基于 CPU 拓扑做全局调优
中断亲和相关 WMI Win32_IRQResource 查询 IRQ 信息 高性能场景:CPU 亲和 + 中断亲和配套

六、边界 & 高频坑点

  1. Win32_Processor 只能读硬件能力,不能查询现有进程的亲和状态,很多人踩坑:在这个类里找 Affinity 相关运行时配置,找不到。
  2. ❗ 虚拟机环境下,NumberOfLogicalProcessors宿主机分配给虚拟机的 vCPU 数量,不是物理机真实 CPU;客户机内绑核仅对 vCPU 生效,宿主机 vCPU 亲和需要在虚拟化层配置。
  3. FeatureSet 是硬件能力标识,不等于当前系统已经开启 APIC / 多核心调度;硬件支持不代表系统启用。
  4. ❗ 多插槽 NUMA 服务器,SocketDesignationNumaNode 字段部分老旧系统 / 精简系统无法正常填充,返回空。
  5. ❗ Get-WmiObject 在新版 Win11/Server2022 已标记弃用,部分新硬件属性只有 Get-CimInstance 才能完整获取。
  6. ❗ 该命令完全无法设置任何亲和,仅做前期规划数据采集。

七、配套实用命令

# 1. 只提取CPU拓扑、NUMA信息(亲和规划核心字段)
Get-WmiObject Win32_Processor | Select SocketDesignation,NumaNode,NumberOfCores,NumberOfLogicalProcessors

# 2. 读取所有进程当前CPU亲和掩码(真正查询亲和)
Get-WmiObject Win32_Process | Select Name,ProcessId,ProcessAffinityMask

# 3. CIM 新版推荐写法
Get-CimInstance Win32_Processor | Select SocketDesignation,NumaNode,NumberOfCores,NumberOfLogicalProcessors
Get-CimInstance Win32_Process | Select Name,ProcessId,ProcessAffinityMask

一、Win32_Process / ProcessAffinityMask 完整解构

核心说明Win32_Process 是 WMI/CIM 中用于管理进程属性的类,ProcessAffinityMask 就是进程级 CPU 亲和掩码;该掩码会被进程内新建线程继承,线程可通过SetThreadAffinityMask单独覆盖。 对应新版 CIM 类:Win32_Process(CIM 兼容同名类)

1. 底层原理

  1. 内核侧存储:EPROCESS 结构体 ProcessAffinityMask 成员,是ULONG_PTR 类型位图
    • bit N = 1:进程允许调度到逻辑 CPU N
    • bit N = 0:禁止调度到逻辑 CPU N
    • 进程新建 ETHREAD 时,默认继承该掩码;线程可单独设置自身ThreadAffinityMask
  2. WMI/CIM 读写链路
    • 查询:WMI 提供程序读取内核 EPROCESS → 封装为ProcessAffinityMask属性输出
    • 设置:WMI 下发请求 → 内核调用NtSetInformationProcess更新 EPROCESS 亲和掩码
  3. 权限校验:修改系统进程、服务进程需要SeIncreaseBasePriorityPrivilege;普通用户仅可修改自身启动的进程
  4. 重要特性:只约束调度选核,不独占核心;已正在运行的线程不会立刻迁移,下一次调度切换才生效

配套关联字段 Win32_Process.ProcessAffinityMask:进程全局亲和掩码 Win32_Process.ProcessPriorityClass:进程优先级(常和绑核一起调优) ✅ 线程单独亲和:WMI没有直接的 Win32_Thread 类可直接修改线程亲和,线程级绑核只能调用原生 Win32 API

2. 依赖文件

  1. WMI 链路(Get-WmiObject)
    • winmgmt.exe WMI 服务
    • CIMWin32.dll Win32 进程信息 WMI 提供程序
    • wbemprox.dll WMI COM 代理
    • System.Management.dll PowerShell Get-WmiObject 底层依赖
  2. CIM 链路(Get-CimInstance,推荐)
    • winrscmd.dllcimprov.dllwsman.dll
  3. 内核依赖
    • ntoskrnl.exe:EPROCESS 管理、NtSetInformationProcess系统调用
    • hal.dll:CPU 拓扑、逻辑核编号
  4. 用户态 API 底层:kernelbase.dll / kernel32.dllSetProcessAffinityMask

3. 依赖关系

✅ 前置依赖

  1. winmgmt/WinRM 服务正常运行
  2. 权限:管理员高权限才能修改系统进程亲和
  3. 掩码合法性:掩码有效 bit 不能超过主机最大逻辑 CPU 编号
  4. 内核无过滤驱动拦截进程信息查询 / 修改

✅ 后置逻辑 更新ProcessAffinityMask → EPROCESS 写入新掩码 → 进程新线程自动继承 → 已有线程下一次调度遵守掩码约束

4. 完整逻辑链路(PowerShell CIM 示例)

Get-CimInstance Win32_Process | Set-CimInstance -Property @{ProcessAffinityMask=0x03}
↓
CIM 调用WinRM/CIM提供程序
↓
CIMWin32提供程序调用NtSetInformationProcess系统调用
↓
ntoskrnl 更新目标进程EPROCESS.ProcessAffinityMask
↓
后续该进程内线程调度时,调度器校验亲和掩码

5. 配套链

组件 作用 关联
SetThreadAffinityMask API 单线程独立亲和 优先级高于进程掩码,WMI 无直接封装
Win32_Processor 获取 CPU 数量、NUMA 节点 用来计算合法亲和掩码
Win32_IRQResource 中断亲和 高性能场景配套同步绑定 IRQ 到同组核心
bcdedit 启动参数 全局调度 / NUMA 配置 整机层面调度基础配置
numactl(Linux)/SetProcessPreferredNumaNode(WinAPI) NUMA 内存亲和 和本掩码组合实现完整高性能调优

6. 边界 & 坑点

  1. 32 位进程在 64 位系统:掩码上限受 32bit 限制,超过 32 核环境极易异常,优先使用 64 位 PowerShell
  2. ❗ 虚拟机内掩码对应的是vCPU 编号,宿主机 vCPU 亲和需要在虚拟化平台单独配置
  3. ❗ 部分受保护系统进程(lsass、ntoskrnl 相关)拒绝修改亲和,直接报错
  4. ❗ 进程重启后ProcessAffinityMask丢失,不会持久化
  5. ProcessAffinityMask=0 非法,会报错;必须至少有 1bit 置 1
  6. ❗ WMI 不支持直接修改单个线程亲和,只能进程级;精细线程绑核需要 C#/C++ 调用原生 API

7. 基础读写示例

# 查询所有进程亲和(CIM推荐)
Get-CimInstance Win32_Process | Select Name,ProcessId,ProcessAffinityMask

# 设置notepad进程亲和为核心0、1(0x03 = 3十进制)
$proc = Get-CimInstance Win32_Process -Filter "Name='notepad.exe'"
if($proc){
    $proc | Set-CimInstance -Property @{ProcessAffinityMask=0x03}
}

二、CPU 亲和掩码 十进制 / 十六进制快速换算脚本

功能:输入核心列表(如 0,2,3)自动生成十进制掩码、十六进制掩码,同时输出可直接用于 ProcessAffinityMask 的代码 支持批量、校验最大逻辑核,防止掩码越界

<#
.SYNOPSIS
CPU亲和掩码快速换算工具
-InputCores : 需要绑定的逻辑核心编号,逗号分隔 例 0,1,4
#>
function Convert-CpuAffinityMask {
    param(
        [Parameter(Mandatory=$true)]
        [string]$InputCores
    )
    # 获取本机最大逻辑CPU编号
    $maxCore = (Get-CimInstance Win32_Processor | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum - 1
    $coreArr = $InputCores.Split(',').Trim() | ForEach-Object {[int]$_} | Sort-Object -Unique

    # 合法性校验
    foreach($c in $coreArr){
        if($c -lt 0 -or $c -gt $maxCore){
            Write-Error "核心 $c 超出本机有效逻辑核范围(0 ~ $maxCore)"
            return
        }
    }
    $mask = 0
    foreach($c in $coreArr){
        $mask += 1 -shl $c
    }
    $hexMask = "0x{0:X}" -f $mask

    $result = [PSCustomObject]@{
        BindCores       = $coreArr -join ","
        DecimalMask     = $mask
        HexMask         = $hexMask
        CimSetCommand   = "`$proc | Set-CimInstance -Property @{ProcessAffinityMask=$hexMask}"
    }
    return $result
}

# ============ 使用示例 ============
Convert-CpuAffinityMask -InputCores "0,1"
Convert-CpuAffinityMask -InputCores "2,3,4"

运行输出示例:

BindCores    : 0,1
DecimalMask  : 3
HexMask      : 0x3
CimSetCommand: $proc | Set-CimInstance -Property @{ProcessAffinityMask=0x3}

三、批量进程自动 NUMA+CPU 亲和部署模板

能力:

  1. 自动读取本机 NUMA 拓扑、每个 NUMA 节点对应的逻辑核心列表
  2. 根据配置,把目标进程绑定到指定 NUMA 节点内 CPU
  3. 同时设置 NUMA 首选节点 + CPU 亲和掩码
  4. 日志输出、跳过不存在进程、权限异常捕获 ⚠️ Windows 原生PowerShell 无直接内置 Cmdlet 设置 NUMA 内存亲和,本模板使用SetProcessPreferredNumaNode Win32 API 实现,兼容 Win10 1709+/Server2016+
<#
.SYNOPSIS
批量进程 NUMA节点 + CPU亲和自动部署模板
#>
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class NumaUtil {
    [DllImport("kernel32.dll")]
    public static extern bool SetProcessPreferredNumaNode(IntPtr hProcess, UInt32 NumaNode);
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    [DllImport("kernel32.dll")]
    public static extern bool CloseHandle(IntPtr hObject);
}
"@

# ====================== 【可修改配置区】======================
# 定义业务分组:进程名 -> 目标NUMA节点
$DeployConfig = @(
    @{ProcessName="notepad.exe"; NumaNode=0},
    @{ProcessName="calc.exe";   NumaNode=1}
)
# ============================================================

$LogPath = "C:\Windows\Temp\NumaAffinity_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
function Write-Log($msg){
    $line = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $msg"
    Add-Content -Path $LogPath -Value $line
    Write-Host $line
}

# 1. 获取NUMA节点与对应逻辑核心映射
$numaInfo = @{}
$procList = Get-CimInstance Win32_Processor
$allNumaNodes = ($procList | Select-Object -ExpandProperty NumaNode -Unique | Sort-Object)
foreach($node in $allNumaNodes){
    $coresInNode = $procList | Where-Object {$_.NumaNode -eq $node} | ForEach-Object {
        $start = ($_.NumberOfLogicalProcessors * $_.DeviceId)
        $end = $start + $_.NumberOfLogicalProcessors -1
        $start..$end
    }
    $numaInfo[$node] = $coresInNode
}
Write-Log "=== 本机NUMA拓扑 ==="
$numaInfo | Out-String | ForEach-Object {Write-Log $_}

# 2. 批量部署
foreach($item in $DeployConfig){
    $procName = $item.ProcessName
    $targetNode = $item.NumaNode
    if(-not $numaInfo.ContainsKey($targetNode)){
        Write-Log "【跳过】NUMA节点 $targetNode 不存在"
        continue
    }
    $coreList = $numaInfo[$targetNode]
    # 计算亲和掩码
    $mask =0
    foreach($c in $coreList){ $mask +=1 -shl $c }
    $hexMask = "0x{0:X}" -f $mask

    $targetProcs = Get-CimInstance Win32_Process -Filter "Name='$procName'" -ErrorAction SilentlyContinue
    if(-not $targetProcs){
        Write-Log "【提示】未找到进程 $procName"
        continue
    }
    foreach($p in $targetProcs){
        $pid = $p.ProcessId
        Write-Log ">>> 处理 $procName PID:$pid , NUMA节点:$targetNode , 亲和掩码:$hexMask"
        # 设置CPU亲和
        try{
            $p | Set-CimInstance -Property @{ProcessAffinityMask=$mask} -ErrorAction Stop
            Write-Log "✅ CPU亲和设置成功"
        }catch{
            Write-Log "❌ CPU亲和设置失败 : $_"
        }
        # 设置NUMA首选节点
        try{
            $h = [NumaUtil]::OpenProcess(0x0400, $false, $pid) # PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION
            if($h -ne [IntPtr]::Zero){
                $ret = [NumaUtil]::SetProcessPreferredNumaNode($h, $targetNode)
                if($ret){ Write-Log "✅ NUMA首选节点设置成功" }
                else{ Write-Log "❌ NUMA节点设置失败" }
                [NumaUtil]::CloseHandle($h)
            }
        }catch{
            Write-Log "❌ NUMA API异常 : $_"
        }
    }
}
Write-Log "==== 部署完成,日志文件: $LogPath ===="

模板使用说明

  1. 必须以管理员身份运行 PowerShell
  2. 修改$DeployConfig数组,填写你的业务进程名与目标 NUMA 节点
  3. 自动采集本机 NUMA 拓扑,自动使用该节点下全部逻辑核心绑定
  4. 日志落地到C:\Windows\Temp\方便巡检审计
  5. 扩展方向:可增加中断亲和同步配置、开机持久化脚本(任务计划)

 

posted @ 2024-03-11 04:53  suv789  阅读(1315)  评论(0)    收藏  举报