如何通过.NET/C#查找CPU内核数?

MrG*_*les 297 .net c# cpu-cores

有没有办法通过.NET/C#找出CPU内核的数量?

PS这是一个直接的代码问题,而不是"我应该使用多线程吗?" 题!:-)

Kev*_*ler 456

您可以获得与处理器相关的几种不同信息:

  1. 物理处理器数量
  2. 核心数量
  3. 逻辑处理器数量.

这些都可以是不同的; 对于具有2个支持双核超线程处理器的计算机,有2个物理处理器,4个核心和8个逻辑处理器.

可以通过Environment类获得逻辑处理器的数量,但其他信息只能通过WMI获得(您可能必须安装一些修补程序或Service Pack才能在某些系统上获取它):

确保将项目中的引用添加到System.Management.dll

物理处理器:

foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_ComputerSystem").Get())
{
    Console.WriteLine("Number Of Physical Processors: {0} ", item["NumberOfProcessors"]);
}
Run Code Online (Sandbox Code Playgroud)

核心:

int coreCount = 0;
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())
{
    coreCount += int.Parse(item["NumberOfCores"].ToString());
}
Console.WriteLine("Number Of Cores: {0}", coreCount);
Run Code Online (Sandbox Code Playgroud)

逻辑处理器:

Console.WriteLine("Number Of Logical Processors: {0}", Environment.ProcessorCount);
Run Code Online (Sandbox Code Playgroud)

要么

foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_ComputerSystem").Get())
{
    Console.WriteLine("Number Of Logical Processors: {0}", item["NumberOfLogicalProcessors"]);
}
Run Code Online (Sandbox Code Playgroud)

从Windows中排除的处理器:

您还可以使用setupapi.dll中的 Windows API调用来发现已从Windows中排除的处理器(例如,通过引导设置),并且无法使用上述方法检测到.下面的代码给出了存在的逻辑处理器总数(我无法弄清楚如何区分物理处理器和逻辑处理器),包括那些已从Windows中排除的处理器:

static void Main(string[] args)
{
    int deviceCount = 0;
    IntPtr deviceList = IntPtr.Zero;
    // GUID for processor classid
    Guid processorGuid = new Guid("{50127dc3-0f36-415e-a6cc-4cb3be910b65}");

    try
    {
        // get a list of all processor devices
        deviceList = SetupDiGetClassDevs(ref processorGuid, "ACPI", IntPtr.Zero, (int)DIGCF.PRESENT);
        // attempt to process each item in the list
        for (int deviceNumber = 0; ; deviceNumber++)
        {
            SP_DEVINFO_DATA deviceInfo = new SP_DEVINFO_DATA();
            deviceInfo.cbSize = Marshal.SizeOf(deviceInfo);

            // attempt to read the device info from the list, if this fails, we're at the end of the list
            if (!SetupDiEnumDeviceInfo(deviceList, deviceNumber, ref deviceInfo))
            {
                deviceCount = deviceNumber - 1;
                break;
            }
        }
    }
    finally
    {
        if (deviceList != IntPtr.Zero) { SetupDiDestroyDeviceInfoList(deviceList); }
    }
    Console.WriteLine("Number of cores: {0}", deviceCount);
}

[DllImport("setupapi.dll", SetLastError = true)]
private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid,
    [MarshalAs(UnmanagedType.LPStr)]String enumerator,
    IntPtr hwndParent,
    Int32 Flags);

[DllImport("setupapi.dll", SetLastError = true)]
private static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

[DllImport("setupapi.dll", SetLastError = true)]
private static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet,
    Int32 MemberIndex,
    ref SP_DEVINFO_DATA DeviceInterfaceData);

[StructLayout(LayoutKind.Sequential)]
private struct SP_DEVINFO_DATA
{
    public int cbSize;
    public Guid ClassGuid;
    public uint DevInst;
    public IntPtr Reserved;
}

private enum DIGCF
{
    DEFAULT = 0x1,
    PRESENT = 0x2,
    ALLCLASSES = 0x4,
    PROFILE = 0x8,
    DEVICEINTERFACE = 0x10,
}
Run Code Online (Sandbox Code Playgroud)

  • @StingyJack:是的,但我希望它的格式更好.必须构建原始字符串查询时,可发现性非常低. (12认同)
  • 所有冰雹WMI! - 该存储库几乎所有东西=) (10认同)
  • WMI Code Creator将帮助进行价值发现和查询创建(它甚至可以在c#/ vb.net中生成存根). (5认同)
  • 它在System.Management.dll中.您是否在项目中包含了对该程序集的引用? (4认同)
  • 很好的信息,thx.我已将此更改为已接受的答案. (2认同)
  • 上面代码中的一个小问题。由于`deviceCount`是从零开始的,核心计数应该像这样输出:`Console.WriteLine("Number of cores: {0}", deviceCount + 1);` (2认同)
  • 您不是通过不放置管理对象和搜索器来引起问题吗? (2认同)

Sam*_*ell 197

Environment.ProcessorCount
Run Code Online (Sandbox Code Playgroud)

[文档]

  • 这给出了逻辑处理器的数量,而不是核心数量. (66认同)
  • 这太简单了,我差点流泪.谢谢你的回复! (10认同)
  • @KevinKibler 从这个问题来看,我怀疑 OP 不理解差异,如果您不知道差异,这可能就是您想要的。 (6认同)

小智 33

WMI查询很慢,因此请尝试仅选择所需的成员,而不是使用Select*.

以下查询需要3.4s:

foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())
Run Code Online (Sandbox Code Playgroud)

虽然这个需要0.122秒:

foreach (var item in new System.Management.ManagementObjectSearcher("Select NumberOfCores from Win32_Processor").Get())
Run Code Online (Sandbox Code Playgroud)


Mit*_*rax 20

Environment.ProcessorCount应该为您提供本地计算机上的核心数.

  • 这给出了逻辑处理器的数量,而不是核心数量. (53认同)

Ost*_*ati 11

看看.NET内部如何在内部说出最少的内容是非常有趣的......它就像下面的"简单"一样:

namespace System.Threading
{
    using System;
    using System.Runtime.CompilerServices;

    internal static class PlatformHelper
    {
        private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 0x7530;
        private static volatile int s_lastProcessorCountRefreshTicks;
        private static volatile int s_processorCount;

        internal static bool IsSingleProcessor
        {
            get
            {
                return (ProcessorCount == 1);
            }
        }

        internal static int ProcessorCount
        {
            get
            {
                int tickCount = Environment.TickCount;
                int num2 = s_processorCount;
                if ((num2 == 0) || ((tickCount - s_lastProcessorCountRefreshTicks) >= 0x7530))
                {
                    s_processorCount = num2 = Environment.ProcessorCount;
                    s_lastProcessorCountRefreshTicks = tickCount;
                }
                return num2;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 但这一切有那么有趣吗?它只是将“Environment.ProcessorCount”中的值缓存一段时间,并且仅由一些与同步相关的类在“内部”使用。`Environment.ProcessorCount` 如何获取其值是提供信息的。另外,看起来您是从反编译器获得此代码,而不仅仅是从[源代码](https://referencesource.microsoft.com/#mscorlib/system/threading/SpinWait.cs,a7801aeb755e9d6f)。 (2认同)

Fab*_*Fab 5

从.NET Framework来源

您也可以在PInvoke上获得它Kernel32.dll

以下代码或多或少SystemInfo.cs来自System.Web源,位于此处

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SYSTEM_INFO
{
  public ushort wProcessorArchitecture;
  public ushort wReserved;
  public uint dwPageSize;
  public IntPtr lpMinimumApplicationAddress;
  public IntPtr lpMaximumApplicationAddress;
  public IntPtr dwActiveProcessorMask;
  public uint dwNumberOfProcessors;
  public uint dwProcessorType;
  public uint dwAllocationGranularity;
  public ushort wProcessorLevel;
  public ushort wProcessorRevision;
}

internal static class SystemInfo 
{
    static int _trueNumberOfProcessors;
    internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);    

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    internal static extern void GetSystemInfo(out SYSTEM_INFO si);

    [DllImport("kernel32.dll")]
    internal static extern int GetProcessAffinityMask(IntPtr handle, out IntPtr processAffinityMask, out IntPtr systemAffinityMask);

    internal static int GetNumProcessCPUs()
    {
      if (SystemInfo._trueNumberOfProcessors == 0)
      {
        SYSTEM_INFO si;
        GetSystemInfo(out si);
        if ((int) si.dwNumberOfProcessors == 1)
        {
          SystemInfo._trueNumberOfProcessors = 1;
        }
        else
        {
          IntPtr processAffinityMask;
          IntPtr systemAffinityMask;
          if (GetProcessAffinityMask(INVALID_HANDLE_VALUE, out processAffinityMask, out systemAffinityMask) == 0)
          {
            SystemInfo._trueNumberOfProcessors = 1;
          }
          else
          {
            int num1 = 0;
            if (IntPtr.Size == 4)
            {
              uint num2 = (uint) (int) processAffinityMask;
              while ((int) num2 != 0)
              {
                if (((int) num2 & 1) == 1)
                  ++num1;
                num2 >>= 1;
              }
            }
            else
            {
              ulong num2 = (ulong) (long) processAffinityMask;
              while ((long) num2 != 0L)
              {
                if (((long) num2 & 1L) == 1L)
                  ++num1;
                num2 >>= 1;
              }
            }
            SystemInfo._trueNumberOfProcessors = num1;
          }
        }
      }
      return SystemInfo._trueNumberOfProcessors;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 尝试过此操作,但它返回逻辑处理器的数量-与调用Environment.ProcessorCount的结果相同。 (2认同)

小智 5

最简单的方法= Environment.ProcessorCount
来自Environment.ProcessorCount属性的示例

using System;

class Sample 
{
    public static void Main() 
    {
        Console.WriteLine("The number of processors " +
            "on this computer is {0}.", 
            Environment.ProcessorCount);
    }
}
Run Code Online (Sandbox Code Playgroud)