Як знайти кількість ядер процесора через .NET / C #?


317

Чи є спосіб через .NET / C # дізнатись кількість ядер CPU?

PS Це питання прямого коду, а не "Чи слід використовувати багатопотоковість?" питання! :-)


7
Чи потрібно знати, скільки ядер існує чи скільки логічних процесорів? Для простого запуску декількох потоків це, мабуть, достатньо, але є сценарії, коли різниця може бути важливою.
Кевін Кіблер

Чи є новіший спосіб зробити це?
MoonKnight

Відповіді:


477

Існує кілька різних відомостей, що стосуються процесорів, які ви можете отримати:

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

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

Кількість логічних процесорів доступна через клас оточення , але інша інформація доступна лише через WMI (і, можливо, вам доведеться встановити деякі виправлення або пакети послуг, щоб отримати їх у деяких системах):

Не забудьте додати посилання у вашому проекті на System.Management.dll в .NET Core, воно доступне (лише для Windows) як пакет NuGet.

Фізичні процесори:

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 API в 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;
                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,
}

14
@StingyJack: Правда, але я хотів би, щоб це було в більш приємному форматі. Виявлення виявляється досить низьким, коли вам доводиться створювати необроблені рядкові запити.
Кевін Кіблер

5
WMI Code Creator допоможе виявити значення та створити запити (він може навіть генерувати заглушки в c # / vb.net).
StingyJack

4
Це в System.Management.dll. Ви включили посилання на цю збірку у свій проект?
Кевін Кіблер

2
Незначна проблема, яка не стосується одного, у вищевказаному коді. Оскільки deviceCountоснована на нулі, то основна кількість повинна виводитися так:Console.WriteLine("Number of cores: {0}", deviceCount + 1);
Франциск Літтеріо

2
Чи не викликаєте ви проблеми, якщо не розпоряджаєтесь об’єктами управління та шукачами?
Бенджамін

205
Environment.ProcessorCount

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


12
Це так красиво просто, що я майже проливаю сльози. Thx для відповіді!
MrGreggles

70
Це дає кількість логічних процесорів, а не кількість ядер.
Кевін Кіблер

8
@KevinKibler З питання, я підозрюю, що ОП не розуміє різниці, і якщо ви не знаєте різниці, це, мабуть, те, що ви хочете.
Гленн Мейнард

1
Це також повертає неправильне підрахунок для багатьох основних систем. Я запускаю два основних процесори dodeca з гіпер-потоком, що дає мені в цілому 48 логічних процесорів. Environment.ProcessorCountврожайність 32.
Аллен Кларк Коупленд-молодший

1
@AlexanderMorou, так, це не забезпечить точних результатів на деяких серверах декількох процесорів. Для цього є виправлення, але його ще не перевірили.
TheLegendaryCopyCoder

35

Запити 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())

1
На якій системі ви це працюєте? Я використовую кілька «Select *» запитів і не займає де - небудь близько 3,4 секунди, випробувані на тисячах комп'ютерів , що моє програмне забезпечення розгортається на. Я роблю Select *, тому що отримую від об’єкта кілька властивостей. Однак я роблю це трохи інакше: створюю ObjectQuery на Select *; отримати ManagementObjectCollection; потім викладіть ManagementObject у програмі ManagementObjectCollection.
deegee

@deegee: ви маєте рацію, сам запит не займає багато часу з "Select *", просто аналіз int внизу повільний, якщо ітерація всіх повернених значень замість просто NumberOfCores.
Алекс Меркадер


10

Досить цікаво бачити, як .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;
            }
        }
    }
}

6

Найпростіший спосіб = 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);
    }
}

Метод Environment.ProcessorCount іноді показує невірні дані (див. Stackoverflow.com/questions/27965962/… )
конструктор

4

З джерела .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;
    }
}

2
Спробував це, але він повертає кількість логічних процесорів - це такий самий результат, як і виклик Environment.ProcessorCount.
Боб Брайан

1

Одним із варіантів було б прочитати дані з реєстру. Стаття MSDN по темі: http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.localmachine(v=vs.71).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.


Це дасть кількість процесорів, які вже доступні в Environment.ProcessorCount, чи є інший подібний спосіб отримати кількість ядер для кожного процесора?
Армен

0

Наступна програма друкує логічні та фізичні ядра 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
*/

6
Це питання позначено тегом .NET; Ваш код не є .NET-кодом.
Вай Ха Лі

-1

Я шукав те саме, але я не хочу встановлювати жодний нукет або пакет оновлень, тому я знайшов це рішення, воно досить просте і прямо вперед, використовуючи це обговорення, я думав, що це буде так легко запустити цю команду 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();

4
Не знаєте, чому ви робите простий WMI-запит настільки складним. Запускати командний рядок WMI як зовнішній процес та аналізувати його вихідний дійсно не потрібно. .NET має вбудовану підтримку WMI-запитів (System.Management.ManagementObjectSearcher), як деякі інші відповіді тут уже проілюстровані. Крім того, я не знаю, чому ви думаєте, для чого потрібні пакети чи сервісні пакети при використанні вбудованої підтримки .NET WMI замість wmic.exe ...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.