不依赖WMI获取CPU物理处理器、核心及逻辑处理器数的方法
不依赖WMI的CPU信息获取方案
直接调用Windows Kernel32.dll提供的原生GetLogicalProcessorInformationEx接口即可完全绕开WMI,不存在WMI服务偶发故障导致调用失败的问题。该接口从Windows 7/Windows Server 2008 R2开始支持所有主流Windows版本,返回结果和原WMI查询的数值完全一致,还能正确适配多物理CPU、超过64逻辑核的多CPU组、大小核架构、虚拟机运行等特殊场景。
对应字段获取逻辑
需要的三个字段可以通过遍历接口返回的结构体直接统计得到:
- 物理处理器(CPU封装)总数:遍历
RelationProcessorPackage类型的返回条目,条目计数就是对应数值,等价于原WMI查询Win32_ComputerSystem拿到的NumberOfProcessors - 物理核心总数:遍历
RelationProcessorCore类型的返回条目,条目计数就是对应数值,等价于原WMI查询Win32_Processor拿到的NumberOfCores - 逻辑处理器总数:统计所有
RelationProcessorCore条目下处理器掩码的置位总数,等价于原WMI查询Win32_Processor拿到的NumberOfLogicalProcessors
VB.NET 实现代码
Imports System.Runtime.InteropServices Private Enum LOGICAL_PROCESSOR_RELATIONSHIP RelationProcessorCore = 0 RelationProcessorPackage = 3 End Enum <StructLayout(LayoutKind.Sequential)> Private Structure GROUP_AFFINITY Public Mask As IntPtr Public Group As UShort <MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> Public Reserved As UShort() End Structure <StructLayout(LayoutKind.Sequential)> Private Structure SYSTEM_LOGICAL_PROCESSOR_INFO_EX Public Relationship As LOGICAL_PROCESSOR_RELATIONSHIP Public Size As UInteger Public Processor As GROUP_AFFINITY End Structure <DllImport("kernel32.dll", SetLastError:=True)> Private Shared Function GetLogicalProcessorInformationEx( RelationshipType As LOGICAL_PROCESSOR_RELATIONSHIP, Buffer As IntPtr, ByRef ReturnedLength As UInteger ) As Boolean End Function Private Sub GetCpuInfoWithoutWmi() Dim bufferLength As UInteger = 0 GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage, IntPtr.Zero, bufferLength) Dim packageBuffer As IntPtr = Marshal.AllocHGlobal(CInt(bufferLength)) Try If GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage, packageBuffer, bufferLength) Then Dim offset As Integer = 0 Dim packageCount As Integer = 0 While offset < bufferLength Dim info = Marshal.PtrToStructure(Of SYSTEM_LOGICAL_PROCESSOR_INFO_EX)(packageBuffer + offset) packageCount += 1 offset += CInt(info.Size) End While _NumberOfPhysicalProcessors = packageCount End If bufferLength = 0 GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, IntPtr.Zero, bufferLength) Dim coreBuffer As IntPtr = Marshal.AllocHGlobal(CInt(bufferLength)) Try If GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, coreBuffer, bufferLength) Then Dim offset As Integer = 0 Dim coreCount As Integer = 0 Dim logicalCount As Integer = 0 While offset < bufferLength Dim info = Marshal.PtrToStructure(Of SYSTEM_LOGICAL_PROCESSOR_INFO_EX)(coreBuffer + offset) coreCount += 1 Dim mask As ULong = info.Processor.Mask.ToInt64() While mask > 0 logicalCount += CInt(mask And 1UL) mask >>= 1 End While offset += CInt(info.Size) End While _NumberOfPhysicalCores = coreCount _NumberOfLogicalCores = logicalCount End If Finally Marshal.FreeHGlobal(coreBuffer) End Try Finally Marshal.FreeHGlobal(packageBuffer) End Try End Sub
注意事项
- 不要使用读取注册表
HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor下键值的方案,该方案在多CPU组、超过64逻辑核、部分虚拟化环境下返回结果不准确。 - 如果使用.NET 7及以上版本,可以直接调用框架内置的
System.Runtime.InteropServices.RuntimeInformation提供的CPU信息接口,底层同样基于上述原生系统API实现,不需要自行编写P/Invoke代码,且完全不依赖WMI。
内容的提问来源于stack exchange,提问作者CTZStef
相关产品推荐
相关产品推荐

