Как узнать количество ядер процессора через.NET/C#?

Есть ли способ через .NET/C# узнать количество ядер процессора?

PS Это прямой вопрос кода, а не "Должен ли я использовать многопоточность?" вопрос!:-)

12 ответов

Решение

Есть несколько разных частей информации, касающихся процессоров, которые вы можете получить:

  1. Количество физических процессоров
  2. Количество ядер
  3. Количество логических процессоров.

Все они могут быть разными; в случае машины с двумя двухъядерными процессорами с поддержкой гиперпоточности имеется 2 физических процессора, 4 ядра и 8 логических процессоров.

Число логических процессоров доступно через класс Environment, но другая информация доступна только через WMI (и вам может потребоваться установить некоторые исправления или пакеты обновления, чтобы получить его на некоторых системах):

Не забудьте добавить ссылку в вашем проекте на 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"]);
}

Ядра:

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);

Логические процессоры:

Console.WriteLine("Number Of Logical Processors: {0}", Environment.ProcessorCount);

ИЛИ ЖЕ

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

Процессоры исключены из Windows:

Вы также можете использовать вызовы API Windows в файле setupapi.dll, чтобы обнаружить процессоры, которые были исключены из 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,
}
Environment.ProcessorCount

[Документация]

Запросы WMI медленные, поэтому старайтесь выбирать только нужные элементы вместо использования Select *.

Следующий запрос занимает 3,4 с:

foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())

В то время как этот занимает 0,122 с:

foreach (var item in new System.Management.ManagementObjectSearcher("Select NumberOfCores from Win32_Processor").Get())

Environment.ProcessorCount должен указать количество ядер на локальном компьютере.

Самый простой способ = 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);
    }
}

Довольно интересно посмотреть, как.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;
            }
        }
    }
}

Из источника.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 
{
    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;
    }
}

Здесь уже есть много ответов, но некоторые из них имеют много положительных голосов и неверны.

.NET Environment.ProcessorCount вернет неверные значения и может привести к критическому сбою, если WMI вашей системы настроен неправильно.

Если вам нужен НАДЕЖНЫЙ способ подсчета ядер, единственный способ - это Win32 API.

Вот фрагмент кода C++:

#include <Windows.h>
#include <vector>

int num_physical_cores()
{
    static int num_cores = []
    {
        DWORD bytes = 0;
        GetLogicalProcessorInformation(nullptr, &bytes);
        std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> coreInfo(bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
        GetLogicalProcessorInformation(coreInfo.data(), &bytes);

        int cores = 0;
        for (auto& info : coreInfo)
        {
            if (info.Relationship == RelationProcessorCore)
                ++cores;
        }
        return cores > 0 ? cores : 1;
    }();
    return num_cores;
}

И поскольку это вопрос.NET C#, вот портированная версия:

[StructLayout(LayoutKind.Sequential)]
struct CACHE_DESCRIPTOR
{
    public byte Level;
    public byte Associativity;
    public ushort LineSize;
    public uint Size;
    public uint Type;
}

[StructLayout(LayoutKind.Explicit)]
struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION
{
    [FieldOffset(0)] public byte ProcessorCore;
    [FieldOffset(0)] public uint NumaNode;
    [FieldOffset(0)] public CACHE_DESCRIPTOR Cache;
    [FieldOffset(0)] private UInt64 Reserved1;
    [FieldOffset(8)] private UInt64 Reserved2;
}

public enum LOGICAL_PROCESSOR_RELATIONSHIP
{
    RelationProcessorCore,
    RelationNumaNode,
    RelationCache,
    RelationProcessorPackage,
    RelationGroup,
    RelationAll = 0xffff
}

struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
{
    public UIntPtr ProcessorMask;
    public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
    public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION ProcessorInformation;
}

[DllImport("kernel32.dll")]
static extern unsafe bool GetLogicalProcessorInformation(SYSTEM_LOGICAL_PROCESSOR_INFORMATION* buffer, out int bufferSize);

static unsafe int GetProcessorCoreCount()
{
    GetLogicalProcessorInformation(null, out int bufferSize);
    int numEntries = bufferSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
    var coreInfo = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[numEntries];

    fixed (SYSTEM_LOGICAL_PROCESSOR_INFORMATION* pCoreInfo = coreInfo)
    {
        GetLogicalProcessorInformation(pCoreInfo, out bufferSize);
        int cores = 0;
        for (int i = 0; i < numEntries; ++i)
        {
            ref SYSTEM_LOGICAL_PROCESSOR_INFORMATION info = ref pCoreInfo[i];
            if (info.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore)
                ++cores;
        }
        return cores > 0 ? cores : 1;
    }
}

public static readonly int NumPhysicalCores = GetProcessorCoreCount();

Одним из вариантов будет чтение данных из реестра. Статья MSDN по теме: http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.localmachine%28v=vs.71%29.aspx)

Я думаю, что процессоры можно найти здесь: HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor

    private void determineNumberOfProcessCores()
    {
        RegistryKey rk = Registry.LocalMachine;
        String[] subKeys = rk.OpenSubKey("HARDWARE").OpenSubKey("DESCRIPTION").OpenSubKey("System").OpenSubKey("CentralProcessor").GetSubKeyNames();

        textBox1.Text = "Total number of cores:" + subKeys.Length.ToString();
    }

Я вполне уверен, что запись реестра будет там на большинстве систем.

Хотя я бы добавил свои 0,02 доллара.

Следующая программа печатает логическое и физическое ядро ​​машины Windows.

#define STRICT
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <omp.h>

template<typename T>
T *AdvanceBytes(T *p, SIZE_T cb)
{
 return reinterpret_cast<T*>(reinterpret_cast<BYTE *>(p) + cb);
}

class EnumLogicalProcessorInformation
{
public:
 EnumLogicalProcessorInformation(LOGICAL_PROCESSOR_RELATIONSHIP Relationship)
  : m_pinfoBase(nullptr), m_pinfoCurrent(nullptr), m_cbRemaining(0)
 {
  DWORD cb = 0;
  if (GetLogicalProcessorInformationEx(Relationship,
                                       nullptr, &cb)) return;
  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;

  m_pinfoBase =
   reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *>
                                     (LocalAlloc(LMEM_FIXED, cb));
  if (!m_pinfoBase) return;

  if (!GetLogicalProcessorInformationEx(Relationship, 
                                        m_pinfoBase, &cb)) return;

  m_pinfoCurrent = m_pinfoBase;
  m_cbRemaining = cb;
 }

 ~EnumLogicalProcessorInformation() { LocalFree(m_pinfoBase); }

 void MoveNext()
 {
  if (m_pinfoCurrent) {
   m_cbRemaining -= m_pinfoCurrent->Size;
   if (m_cbRemaining) {
    m_pinfoCurrent = AdvanceBytes(m_pinfoCurrent,
                                  m_pinfoCurrent->Size);
   } else {
    m_pinfoCurrent = nullptr;
   }
  }
 }

 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Current()
                                         { return m_pinfoCurrent; }
private:
 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *m_pinfoBase;
 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *m_pinfoCurrent;
 DWORD m_cbRemaining;
};


int __cdecl main(int argc, char **argv)
{
  int numLogicalCore = 0;
  int numPhysicalCore = 0;

  for (EnumLogicalProcessorInformation enumInfo(RelationProcessorCore);
      auto pinfo = enumInfo.Current(); enumInfo.MoveNext()) 
  {
      int numThreadPerCore = (pinfo->Processor.Flags == LTP_PC_SMT) ? 2 : 1;
      // std::cout << "thread per core: "<< numThreadPerCore << std::endl;
      numLogicalCore += numThreadPerCore;
      numPhysicalCore += 1;
  }

  printf ("Number of physical core = %d , Number of Logical core = %d \n", numPhysicalCore, numLogicalCore );

 char c = getchar(); /* just to wait on to see the results in the command prompt */
 return 0;
}

/*
I tested with Intel Xeon four cores with hyper threading and here is the result
Number of physical core = 4 , Number of Logical core = 8
*/

Вы можете использовать этот класс:

      public static class CpuCores
{
    private static int cores = 0;
    
    public static int Number
    { 
        get
        {
            if (cores > 0) return cores;

            RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Class\" +
                "{50127dc3-0f36-415e-a6cc-4cb3be910b65}");
            if (key == null)
            {
                cores = Environment.ProcessorCount;
                return cores;
            }
            string[] subkeys = key.GetSubKeyNames();
            key.Close();
            cores = 0;
            if (subkeys != null && subkeys.Length > 0) foreach (string s in subkeys)
            {
                if (s.Length != 4) continue;
                int n;
                if (int.TryParse(s, out n) && ++n > cores) cores = n;
            }
            if (cores <= 0) cores = Environment.ProcessorCount;
            return cores;
        } 
    }
}

Я искал то же самое, но я не хочу устанавливать какой-либо nuget или пакет обновления, поэтому я нашел это решение, оно довольно простое и прямолинейное, используя это обсуждение, я подумал, что было бы так легко выполнить эту команду WMIC и получить это значение, вот код C#. Вам нужно только использовать пространство имен System.Management (и пару стандартных пространств имен для процесса и т. Д.).

    string fileName = Path.Combine(Environment.SystemDirectory, "wbem", "wmic.exe");
    string arguments = @"cpu get NumberOfCores";

    Process process = new Process
    {
        StartInfo =
        {
            FileName = fileName,
            Arguments = arguments,
            UseShellExecute = false,
            CreateNoWindow = true,
            RedirectStandardOutput = true,
            RedirectStandardError = true
        }
    };

    process.Start();

    StreamReader output = process.StandardOutput;
    Console.WriteLine(output.ReadToEnd());


    process.WaitForExit();
    int exitCode = process.ExitCode;
    process.Close();
Другие вопросы по тегам