.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.