.NET / C #을 통해 CPU 코어 수를 찾는 방법은 무엇입니까?


317

.NET / C # 을 통해 CPU 코어 수를 찾는 방법이 있습니까?

PS 이것은 "멀티 스레딩을 사용해야합니까?"가 아닌 간단한 코드 질문입니다. 질문! :-)


7
몇 개의 코어가 있는지 또는 몇 개의 논리 프로세서가 있는지 알아야합니까? 여러 스레드를 실행하는 것만으로도 충분하지만 차이가 중요한 시나리오가 있습니다.
— Kevin Kibler

이 작업을 수행하는 새로운 방법이 있습니까?
— MoonKnight

답변:


477

얻을 수있는 프로세서와 관련된 여러 가지 정보가 있습니다.

  1. 물리적 프로세서 수
  2. 코어 수
  3. 논리 프로세서 수

이것들은 다를 수 있습니다. 2 개의 듀얼 코어 하이퍼 스레딩 가능 프로세서가있는 머신의 경우 2 개의 물리적 프로세서, 4 개의 코어 및 8 개의 논리 프로세서가 있습니다.

논리 프로세서의 수는 Environment 클래스를 통해 사용 가능 하지만 다른 정보는 WMI를 통해서만 사용 가능합니다 ( 일부 시스템 에서는이를 위해 일부 핫픽스 또는 서비스 팩 을 설치해야 할 수도 있음 ).

프로젝트에서 System.Management.dll에 참조를 추가해야합니다 . .NET Core에서이 패키지는 NuGet 패키지로 제공됩니다 (Windows 만 해당).

물리적 프로세서 :

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에서 제외 된 프로세서 :

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;
                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 : 맞습니다.하지만 더 좋은 형식이기를 바랍니다. 원시 문자열 쿼리를 작성해야 할 때 검색 가능성이 매우 낮습니다.
— Kevin Kibler

5
WMI Code Creator는 가치 발견 및 쿼리 생성을 도와줍니다 (c # / vb.net에서 스텁을 생성 할 수도 있음).
— StingyJack

4
System.Management.dll에 있습니다. 프로젝트에 해당 어셈블리에 대한 참조를 포함 시켰습니까?
— Kevin Kibler

2
위의 코드에서 사소한 문제입니다. 이후 deviceCount: 0부터 시작, 코어 수는 다음과 같이 출력한다Console.WriteLine("Number of cores: {0}", deviceCount + 1);
— 프란시스 Litterio

2
관리 개체와 검색자를 폐기하지 않아 문제가 발생하지 않습니까?
— Benjamin

205
Environment.ProcessorCount

[선적 서류 비치]


12
눈물을 흘리기 시작하는 것은 매우 아름답습니다. 회신을위한 Thx!
— MrGreggles

70
이것은 코어 수가 아닌 논리 프로세서 수를 제공합니다.
— Kevin Kibler

8
@KevinKibler 질문에서 OP는 차이를 이해하지 못한다고 생각합니다. 차이를 모른다면 이것이 아마도 당신이 원하는 것입니다.
— Glenn Maynard 2016 년

1
또한 많은 코어 시스템에서 잘못된 수를 반환합니다. 하이퍼 스레딩을 사용하여 두 개의 dodeca 코어 프로세서를 실행하고 있으며 총 48 개의 논리 프로세서를 제공합니다. Environment.ProcessorCount32를 생산.
— Allen Clark Copeland Jr

1
@AlexanderMorou, 예. 일부 다중 CPU 서버에서 정확한 결과를 제공하지 못합니다. 이에 대한 수정이 있지만 아직 테스트하지 않았습니다.
— 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
어떤 시스템에서이 시스템을 실행하고 있습니까? 여러 개의 "선택 *"쿼리를 사용하고는 고려하지 않습니다 어디서나 내 소프트웨어에 배포되는 수천 대의 컴퓨터에서 테스트 가까운 3.4 초. 객체에서 여러 속성을 가져 오기 때문에 Select *를 수행합니다. 그러나 나는 조금 다르다 : Select *에 ObjectQuery를 작성하십시오. ManagementObjectCollection을 가져옵니다. 그런 다음 ManagementObjectCollection의 각 ManagementObject를 찾습니다.
— deegee

@deegee : 맞습니다. "Select *"를 사용하면 쿼리 자체가 훨씬 오래 걸리지 않습니다. NumberOfCores 대신 반환되는 모든 값을 반복하면 아래의 int 구문 분석이 느려집니다.
— Aleix Mercader


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


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 호출과 동일한 결과입니다.
— Bob Bryan

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에서 이미 사용 가능한 많은 프로세서를 제공 할 것입니다. 각 프로세서마다 코어 수를 얻는 다른 방법이 있습니까?
— Armen

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 코드가 아닙니다.
— Wai Ha Lee

-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)를 기본적으로 지원합니다. 여기에 나와있는 다른 답변 중 일부가 이미 나와 있습니다. 또한 wmic.exe 대신 .NET의 내장 WMI 지원을 사용할 때 너겟 패키지 나 서비스 팩이 필요한 이유를 모르겠습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.