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
- 内核主体:
ntoskrnl.exe(调度器核心、ETHREAD/EPROCESS 管理) - 内核模块:
ci.dll、hal.dll(硬件抽象层 HAL,负责 CPU 拓扑、逻辑核心编号上报) - 用户态 API 导出:
kernel32.dll/kernelbase.dll(封装SetProcessAffinityMask等 Win32 API) - 配套工具程序:
taskmgr.exe、wmic.exe、powershell、start.exe
Linux
- 内核核心:
kernel/sched/调度源码,cpumask核心库 - 系统调用入口:
sys_sched_setaffinity - 用户态工具依赖 libc:
shturl.(封装sched_setaffinity) - 工具:
taskset、numactl
三、依赖关系
✅ 前置依赖
- CPU 硬件:多逻辑核心(单核 CPU 设置亲和无意义);操作系统识别正确 CPU 拓扑(HAL/ACPI 上报核心编号正常)
- 权限约束
- Windows:默认普通用户只能修改自身进程亲和;修改系统进程、服务进程亲和需要SeIncreaseBasePriorityPrivilege 高权限
- Linux:普通用户可修改自己进程;root 可修改任意进程
- 调度器未被第三方内核模块 / 实时补丁接管(如某些工控实时内核替换调度器,亲和逻辑可能改动)
- 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 亲和 |
六、边界、限制、高频坑点
- ❗ 亲和只是调度约束,不是独占 只是限制线程能跑哪些核,不独占核心;其他进程依然可以调度到这些核心。要实现核心独占,需要配合CPU 隔离(isolcpus Linux / 核心预留 Windows)
- ❗ 掩码不能超出系统有效逻辑 CPU 总数 比如主机总共 4 核(0~3),掩码设置 0x10(bit4)直接报错
- ❗ 进程亲和是新建线程默认值,线程可单独覆盖 进程设置完亲和后,子线程可以调用
SetThreadAffinityMask单独使用不同掩码 - ❗ Windows 部分系统进程、内核线程不允许修改亲和(受内核保护)
- ❗ 热插拔 CPU 场景:CPU 离线后,原有亲和掩码如果包含离线核心,行为由系统版本决定(新版自动屏蔽失效 bit)
- ❗ 超线程 SMT 场景:逻辑核是独立编号,亲和可以单独绑定单个逻辑核
- ❗ 不具备实时性:普通 CFS/Windows 调度器只是遵守掩码,不能保证确定性延迟;工业实时场景需要 RTOS / 实时内核
- ❗ 虚拟机内 CPU 亲和:宿主机 vCPU 亲和 和 客户机内 CPU 亲和是两层独立控制,极易混淆
- ❗ 休眠 / 快速启动场景,亲和配置不持久,进程重启后亲和恢复默认
七、常用实操命令速记
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 亲和配套落地。
一、低延迟 / 实时业务场景(最核心)
- 工控实时程序、运动控制、PLC 配套软件 业务线程绑定固定核心,减少跨核迁移带来的缓存失效、上下文切换抖动,保证调度确定性;工业设备、机器视觉采集、数据采集程序高频使用。
- 高频交易、行情接收、低延迟网关 收包 / 处理线程固定在指定核心,避免系统其他进程、内核线程频繁抢占;一般配套网卡 IRQ 亲和绑定同一组核心。
- 音视频实时编码 / 推流 编码线程绑定专属核心,防止突发调度抖动导致帧丢包、音画卡顿。
二、服务器高性能业务优化(数据库、缓存)
- MySQL、PostgreSQL、Redis、Elasticsearch 大内存数据库 / 缓存跑在 NUMA 服务器上,CPU 亲和 + NUMA 内存亲和组合,线程固定节点内核心,内存优先分配本地节点内存,规避跨 NUMA 访问延迟。
- 消息队列(Kafka、RocketMQ) IO 线程、网络线程单独绑核,隔离业务计算线程,避免 IO 中断和业务争抢核心。
- 高性能计算 HPC、仿真、渲染 并行计算任务绑定一组核心,减少线程迁移,提升 L1/L2 缓存命中率。
三、虚拟化 & 容器场景
- 宿主机 vCPU 绑核 KVM/VMware,把虚拟机 vCPU 固定到宿主机物理核心,避免不同虚拟机 vCPU 互相抢占,提升虚拟机稳定性;云主机、隔离租户场景常用。
- 容器(Docker/K8s)CPU 绑核
--cpuset-cpus,限定容器内进程只能跑指定核心,实现资源硬隔离,避免业务之间相互干扰。 - 直通设备虚拟机(GPU / 网卡直通) vCPU + 设备中断绑定同一核心,降低直通设备 IO 延迟。
四、多实例服务隔离场景
- 多实例网关、多进程采集程序 多个独立业务进程分别绑定不同核心,实现资源物理隔离,防止某一个实例 CPU 打满拖垮其他业务。
- 压测工具、性能测试 压测进程单独绑核,精准控制压测算力,避免系统其他进程干扰性能指标采集,保证测试数据可信。
五、系统内核、驱动调优场景
- DPDK、VPP 高性能数据面 DPDK 轮询线程(PMD 线程)强制绑核,同时关闭 irqbalance、中断亲和对齐 PMD 核心,是标准落地方案。
- 存储高性能服务(iSCSI、NVMe 存储网关) 存储 IO 处理线程绑定核心,配合 NVMe 队列中断亲和,降低 IO 时延。
六、兼容 / 缺陷规避场景
- 老旧闭源软件、单线程老程序 部分老旧软件多核心下存在 bug、逻辑异常,强制限制仅在单个核心运行保证稳定性。
- 特定硬件兼容性问题 部分外设驱动、加密卡程序在多核心调度时偶发异常,绑核规避异常。
七、不适合使用 CPU 亲和的场景(避坑)
- 通用 Web 服务、普通业务后台:流量波动大,绑核容易出现核心负载不均衡,操作系统自动调度效果更好
- 负载波动极大的弹性业务:固定核心会造成资源浪费或者瓶颈
- 单核轻量小程序:无收益,增加运维复杂度
配套落地标准组合清单
低延迟高性能标准方案:
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 ProcessorAffinity、start /affinity |
SetInterruptAffinity、WMI、注册表 IRQ 掩码设备管理器、bcd 全局中断配置 |
SetProcessPreferredNumaNode、GetNumaHighestNodeNumberPowerShell NUMA 相关接口 |
| Linux 配套 API / 工具 | sched_setaffinity、taskset |
/proc/irq/[num]/smp_affinity、irqbalance |
set_mempolicy、numactl、numastat |
| 生效范围 | 仅约束软件线程调度,不影响硬件中断、内核 DPC(默认) | 仅约束硬件中断投递,不约束普通业务线程 | 同时影响内存分配位置和调度节点偏好 |
| 是否独占核心 | ❌ 只是调度约束,核心可被其他线程 / 中断抢占 | ❌ 仅约束中断投递目标,核心可被进程抢占 | ❌ 优先策略,非强制独占,可跨节点分配内存 |
| 持久特性 | 进程重启失效,运行时临时生效 | 默认临时生效;部分可写入注册表 / 内核参数持久化 | 进程重启失效,可配置进程默认 NUMA 策略 |
| 关键独立边界 | 无法限制硬件中断跑到绑定核上,容易出现 “线程绑核但中断抢占该核” 的性能坑 | 只管硬件中断,业务线程依然会随机跑在其他核心,需要配合 CPU 亲和一起使用 | 不精细控制单 CPU 核心,是以NUMA 节点(一组 CPU + 本地内存)为单位,节点内核心仍可自由调度 |
| 典型组合方案 | ✅ 高性能服务器标准组合:CPU 亲和 + 中断亲和 + NUMA 亲和业务线程绑定节点内 CPU → 网卡 / 存储中断绑定同组 CPU → 内存优先分配本节点本地内存,消除跨 NUMA 访问开销 |
补充关键术语精简说明
- DPC 亲和:属于广义中断体系(延迟过程调用),和 IRQ 亲和配套,Windows 高频调优项;
- IdealProcessor(理想处理器):Windows 专属,是软偏好,不属于严格 CPU 硬亲和;
- irqbalance:Linux 守护进程,自动均衡中断,高性能场景一般手动关闭,手动固化中断亲和;
- 虚拟机场景分层:宿主机 vCPU 亲和、宿主机中断亲和、客户机内 CPU/NUMA 亲和,三层相互独立,极易混淆。
高频踩坑汇总
- 只配置 CPU 亲和,不配置中断亲和:业务线程绑定核心后,大量网卡中断持续抢占该核心,性能反而下降;
- NUMA 机器只绑 CPU 不设置 NUMA 内存策略:线程跑在节点 0 的 CPU,但内存分配到节点 1,跨节点访问延迟极高;
- 超线程 SMT 场景:亲和掩码绑定逻辑核,中断也需要对应绑定同逻辑核,不能只看物理核编号。
CPU 亲和力(CPU affinity)是指将一个进程或线程限制在特定的 CPU 核心上运行的能力。
CPU 亲和力可以用来指定一个进程或线程在多核系统中使用哪些 CPU 核心来执行其任务。
这种技术可以优化系统性能、减少竞争,并帮助避免缓存伪共享等问题。
CPU 亲和性在处理缓存伪共享等问题上可以发挥重要作用:
-
缓存效果:在多核系统中,不同核心的缓存是相互独立的,当多个线程同时访问同一块数据时,可能导致数据在不同核心的缓存之间被频繁地传输,这就是缓存伪共享。通过设置 CPU 亲和性,可以将相关的线程绑定到同一个或相邻的核心上,减少了数据在不同核心之间的传输,降低了缓存伪共享的影响,提高了缓存的命中率和程序的性能。
-
资源竞争:缓存伪共享会增加不必要的内存访问和数据传输,导致多个核心之间的资源竞争,影响了系统的性能。通过设置 CPU 亲和性,可以将相关的线程绑定到同一组或同一个核心上,减少了对共享数据的竞争,降低了资源争用,提高了系统的整体性能。
-
NUMA 效应:在 NUMA 架构中,每个内存节点与特定的 CPU 核心相关联,跨节点访问内存会引入额外的延迟和带宽消耗。缓存伪共享会导致跨节点的内存访问增多,进一步加剧了 NUMA 效应的影响。通过设置 CPU 亲和性,可以将相关的线程绑定到同一个 NUMA 节点上的核心上,减少了跨节点的内存访问,降低了 NUMA 效应的影响,提高了内存访问的效率。
CPU affinity(CPU 亲和性)是指将进程或线程与特定的 CPU 核心进行绑定,使其在执行过程中只在指定的核心上运行。它可以解决以下一些问题:
-
缓存效果:CPU 有多级缓存,而每个核心都有自己的缓存。当进程或线程频繁地在多个核心间切换执行时,会导致缓存的失效,从而降低了缓存的命中率,影响了程序的性能。通过设置 CPU 亲和性,可以将进程或线程绑定到特定的核心上,增加了缓存的命中率,提高了程序的执行效率。
-
资源竞争:在多核系统中,多个进程或线程同时运行时可能会共享某些资源,如内存、缓存、总线等。如果这些进程或线程频繁地在不同核心间切换执行,就会增加资源的竞争和争用,导致性能下降。通过设置 CPU 亲和性,可以减少进程或线程之间的资源竞争,提高系统的整体性能。
-
负载均衡:在一个系统中,不同的应用程序或任务可能有不同的计算量和优先级。通过设置 CPU 亲和性,可以将计算密集型的任务绑定到一个或多个特定的核心上,将高优先级的任务分配给更强大的核心,实现负载均衡和性能优化。
-
实时性:对于一些实时应用程序,如音视频处理、数据采集等,对响应时间要求较高。通过设置 CPU 亲和性,可以确保这些实时任务在指定的核心上独占运行,避免被其他任务的干扰,提高系统的实时性能。
-
可预测性:在一些对延迟敏感的应用中,如高频交易系统、游戏引擎等,需要保证系统的响应时间可预测。通过设置 CPU 亲和性,可以减少进程或线程切换的开销,提高系统的可预测性和稳定性。
-
避免 NUMA 效应:在 NUMA(Non-Uniform Memory Access)架构的系统中,不同的 CPU 核心访问内存的延迟和带宽可能不同。通过设置 CPU 亲和性,可以将进程或线程与距离其内存节点更近的 CPU 核心绑定,减少 NUMA 效应对性能造成的影响,提高内存访问效率。
-
减少上下文切换:在多核系统中,如果进程或线程频繁地在不同核心间切换执行,会增加上下文切换的开销,降低系统的性能。通过设置 CPU 亲和性,可以减少核心间的任务切换,减少上下文切换的次数,提高系统的效率。
-
节能和热管理:在移动设备或数据中心等对能耗和散热有一定要求的场景中,通过设置 CPU 亲和性,可以将任务集中在少数核心上运行,让其他核心处于休眠或低功耗状态,从而实现节能和热管理的效果。
-
提高可靠性:通过设置 CPU 亲和性,可以降低系统中不必要的干扰和竞争,提高系统的稳定性和可靠性。特别是在一些对系统稳定性要求较高的场景中,合理设置 CPU 亲和性可以有效减少意外情况的发生,提升系统的可靠性。
为什么需要 CPU 亲和力?
- 性能优化:通过将特定进程绑定到特定的 CPU 核心上,可以避免在不同核心之间频繁切换,提高缓存命中率,从而提升性能。
- 避免竞争:在多核系统中,不同进程、线程对 CPU 核心的竞争可能导致性能下降。通过设置 CPU 亲和力,可以避免这种竞争。
- 确保实时性:对于需要实时性的任务,可以通过 CPU 亲和力确保任务能够在指定的 CPU 核心上及时执行,避免被其他任务干扰。
如何设置 CPU 亲和力?
- 操作系统支持:首先,操作系统必须支持 CPU 亲和力设置,比如 Linux、Windows 等主流操作系统一般都支持这一功能。
- 工具或接口:通常可以通过操作系统提供的工具或接口来设置 CPU 亲和力,比如 Linux 下的
taskset命令。 - 编程接口:对于程序员而言,也可以通过编程接口(如 POSIX 线程库提供的函数)来设置线程的 CPU 亲和力。
CPU亲和力(CPU affinity)是指将一个或多个进程或线程绑定到特定的CPU核心或处理器上运行的能力。它可以通过操作系统提供的API或工具来实现。
CPU亲和力的作用如下:
-
优化性能:通过将进程或线程与特定的CPU核心绑定,可以减少在不同核心之间的频繁切换,从而降低了缓存失效、上下文切换等带来的开销,提高了系统的整体性能。
-
控制资源分配:通过设置CPU亲和力,可以控制特定进程或线程使用的CPU资源,以便更好地分配系统资源,提高整体的系统可用性和吞吐量。
-
减少干扰:将关键任务或实时任务绑定到特定的CPU核心,可以避免其他任务对其产生干扰,提高任务的响应性和实时性。
-
节能和降温:通过合理设置CPU亲和力,可以选择性地关闭或休眠未使用的CPU核心,从而减少功耗和降低温度,延长电池寿命等。
然而,不正确或滥用CPU亲和力可能带来以下影响:
-
负载不均衡:如果某些CPU核心被过度绑定,而其他核心空闲,可能导致负载不均衡,使得系统无法充分利用所有的处理能力。
-
资源竞争:当多个进程或线程被绑定到同一个CPU核心时,它们可能会发生资源竞争,导致性能下降或不稳定。
-
硬件局限:某些特殊的处理器架构或操作系统可能对CPU亲和力的支持有限,可能无法完全实现预期的效果。
在 Windows 系统中:
-
查看当前CPU亲和力设置:
- 在任务管理器中可以查看每个进程所在的CPU核心。
- 打开任务管理器(Ctrl + Shift + Esc)。
- 在“详细信息”选项卡中,右键单击列标题,选择“选择列”。
- 勾选“CPU 亲和性”列,即可查看每个进程的CPU亲和力设置。
- 在任务管理器中可以查看每个进程所在的CPU核心。
在 Windows 系统中:
-
打开 PowerShell 命令行,输入以下命令来获取 CPU 的详细信息:
bashCopy CodeGet-WmiObject -Class Win32_Processor | Select-Object -Property * -
在输出结果中查找与CPU特性相关的信息,寻找是否有关于亲和力设置的支持信息。
Get-WmiObject -Class Win32_Processor 完整解构
命令:
Get-WmiObject -Class Win32_Processor | Select-Object -Property *补充说明:Get-WmiObject是旧 WMI 接口,新版推荐Get-CimInstance Win32_Processor;Win32_Processor 类本身只用于读取 CPU 硬件 / 能力属性,不能直接设置 CPU 亲和,亲和属于进程 / 线程属性,不在此类
一、底层原理
- 基础架构
Get-WmiObject→ WMI 服务(winmgmt.exe)→ WMI 提供程序CIMWin32.dll→ 读取系统内核、HAL、注册表、CPUID 信息,组装成Win32_ProcessorWMI 实例返回。Win32_Processor是只读硬件描述类,描述物理 CPU / 逻辑处理器的硬件能力、拓扑、支持特性;不存储、不管理运行时 CPU 亲和配置。
CPU 亲和是进程 / 线程的运行时调度属性,对应 WMI 类是
Win32_Process(ProcessAffinityMask属性),不是 Win32_Processor。
-
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 访问延迟 补充备注
- Win32_Processor全部为硬件静态能力字段,不存储任何进程 / 线程实时亲和配置;进程亲和掩码读取 / 修改使用
Win32_Process.ProcessAffinityMask - 虚拟机环境下,该类读取到的是虚拟化暴露的 vCPU 拓扑,不是物理主机真实 CPU 信息
- 部分老旧系统、精简系统中
SocketDesignation、NumaNode可能为空,无法正常采集 NUMA 拓扑
- Win32_Processor全部为硬件静态能力字段,不存储任何进程 / 线程实时亲和配置;进程亲和掩码读取 / 修改使用
⚠️ 重点边界:Win32_Processor 没有任何字段可以读取 / 修改当前正在运行进程的 CPU 亲和值。 ✅ 进程亲和掩码读取要使用:
Get-WmiObject Win32_Process | Select-Object Name,ProcessId,ProcessAffinityMask
- 数据来源
- CPU 基础拓扑、核心数量:
hal.dll+ ACPI、CPUID 指令 - NUMA 节点信息:内核内存管理器、
ntoskrnl.exe - FeatureSet 等能力位:直接执行 CPUID 指令采集
二、依赖文件
- 主程序:
Get-WmiObject属于System.Management(.NET),PowerShell 内置 - WMI 核心组件
winmgmt.exe:WMI 服务进程CIMWin32.dll:Win32 信息 WMI 提供程序(核心)wbemprox.dll、wbemsvc.dll:WMI COM 代理
- 内核 & 硬件抽象层
ntoskrnl.exe:内核,CPU 拓扑、NUMA 信息hal.dll:硬件抽象层,CPUID、APIC、多核心拓扑上报
- .NET 程序集:
System.Management.dll(Get-WmiObject 底层依赖)
新版 CIM(Get-CimInstance)依赖:
wsman.dll、cimprov.dll,不再强依赖传统 WMI
三、依赖关系
✅ 前置依赖
winmgmtWMI 服务正常运行(sc query winmgmt)- 系统能够正常读取 ACPI 表、CPUID 指令;虚拟机内需要虚拟机暴露 CPU 拓扑信息
- 权限:普通用户即可读取 Win32_Processor 硬件信息,不需要管理员
- 无内核级过滤驱动拦截 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 亲和 + 中断亲和配套 |
六、边界 & 高频坑点
- ❗ Win32_Processor 只能读硬件能力,不能查询现有进程的亲和状态,很多人踩坑:在这个类里找 Affinity 相关运行时配置,找不到。
- ❗ 虚拟机环境下,
NumberOfLogicalProcessors是宿主机分配给虚拟机的 vCPU 数量,不是物理机真实 CPU;客户机内绑核仅对 vCPU 生效,宿主机 vCPU 亲和需要在虚拟化层配置。 - ❗
FeatureSet是硬件能力标识,不等于当前系统已经开启 APIC / 多核心调度;硬件支持不代表系统启用。 - ❗ 多插槽 NUMA 服务器,
SocketDesignation、NumaNode字段部分老旧系统 / 精简系统无法正常填充,返回空。 - ❗ Get-WmiObject 在新版 Win11/Server2022 已标记弃用,部分新硬件属性只有 Get-CimInstance 才能完整获取。
- ❗ 该命令完全无法设置任何亲和,仅做前期规划数据采集。
七、配套实用命令
# 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. 底层原理
- 内核侧存储:
EPROCESS结构体ProcessAffinityMask成员,是ULONG_PTR 类型位图- bit N = 1:进程允许调度到逻辑 CPU N
- bit N = 0:禁止调度到逻辑 CPU N
- 进程新建 ETHREAD 时,默认继承该掩码;线程可单独设置自身
ThreadAffinityMask
- WMI/CIM 读写链路
- 查询:WMI 提供程序读取内核 EPROCESS → 封装为
ProcessAffinityMask属性输出 - 设置:WMI 下发请求 → 内核调用
NtSetInformationProcess更新 EPROCESS 亲和掩码
- 查询:WMI 提供程序读取内核 EPROCESS → 封装为
- 权限校验:修改系统进程、服务进程需要
SeIncreaseBasePriorityPrivilege;普通用户仅可修改自身启动的进程 - 重要特性:只约束调度选核,不独占核心;已正在运行的线程不会立刻迁移,下一次调度切换才生效
配套关联字段
Win32_Process.ProcessAffinityMask:进程全局亲和掩码Win32_Process.ProcessPriorityClass:进程优先级(常和绑核一起调优) ✅ 线程单独亲和:WMI没有直接的 Win32_Thread 类可直接修改线程亲和,线程级绑核只能调用原生 Win32 API
2. 依赖文件
- WMI 链路(Get-WmiObject)
winmgmt.exeWMI 服务CIMWin32.dllWin32 进程信息 WMI 提供程序wbemprox.dllWMI COM 代理System.Management.dllPowerShell Get-WmiObject 底层依赖
- CIM 链路(Get-CimInstance,推荐)
winrscmd.dll、cimprov.dll、wsman.dll
- 内核依赖
ntoskrnl.exe:EPROCESS 管理、NtSetInformationProcess系统调用hal.dll:CPU 拓扑、逻辑核编号
- 用户态 API 底层:
kernelbase.dll/kernel32.dll→SetProcessAffinityMask
3. 依赖关系
✅ 前置依赖
- winmgmt/WinRM 服务正常运行
- 权限:管理员高权限才能修改系统进程亲和
- 掩码合法性:掩码有效 bit 不能超过主机最大逻辑 CPU 编号
- 内核无过滤驱动拦截进程信息查询 / 修改
✅ 后置逻辑 更新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. 边界 & 坑点
- ❗ 32 位进程在 64 位系统:掩码上限受 32bit 限制,超过 32 核环境极易异常,优先使用 64 位 PowerShell
- ❗ 虚拟机内掩码对应的是vCPU 编号,宿主机 vCPU 亲和需要在虚拟化平台单独配置
- ❗ 部分受保护系统进程(lsass、ntoskrnl 相关)拒绝修改亲和,直接报错
- ❗ 进程重启后
ProcessAffinityMask丢失,不会持久化 - ❗
ProcessAffinityMask=0非法,会报错;必须至少有 1bit 置 1 - ❗ 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 亲和部署模板
能力:
- 自动读取本机 NUMA 拓扑、每个 NUMA 节点对应的逻辑核心列表
- 根据配置,把目标进程绑定到指定 NUMA 节点内 CPU
- 同时设置 NUMA 首选节点 + CPU 亲和掩码
- 日志输出、跳过不存在进程、权限异常捕获 ⚠️ Windows 原生PowerShell 无直接内置 Cmdlet 设置 NUMA 内存亲和,本模板使用
SetProcessPreferredNumaNodeWin32 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 ===="
模板使用说明
- 必须以管理员身份运行 PowerShell
- 修改
$DeployConfig数组,填写你的业务进程名与目标 NUMA 节点 - 自动采集本机 NUMA 拓扑,自动使用该节点下全部逻辑核心绑定
- 日志落地到
C:\Windows\Temp\方便巡检审计 - 扩展方向:可增加中断亲和同步配置、开机持久化脚本(任务计划)

浙公网安备 33010602011771号