Bagaimana menemukan Jumlah Core CPU melalui .NET / C #?


317

Apakah ada cara via .NET / C # untuk mengetahui jumlah core CPU?

PS Ini adalah pertanyaan kode langsung, bukan "Haruskah saya menggunakan multi-threading?" pertanyaan! :-)


7
Apakah Anda perlu tahu berapa banyak core yang ada atau berapa banyak prosesor logis yang ada? Untuk hanya menjalankan beberapa utas, mungkin keduanya cukup, tetapi ada skenario di mana perbedaannya mungkin penting.
Kevin Kibler

Apakah ada cara yang lebih baru untuk melakukan ini?
MoonKnight

Jawaban:


477

Ada beberapa informasi berbeda yang berkaitan dengan prosesor yang bisa Anda dapatkan:

  1. Jumlah prosesor fisik
  2. Jumlah inti
  3. Jumlah prosesor logis.

Ini semua bisa berbeda; dalam kasus mesin dengan 2 prosesor dual-core hyper-threading-enabled, ada 2 prosesor fisik, 4 core, dan 8 prosesor logis.

Jumlah prosesor logis tersedia melalui kelas Lingkungan , tetapi informasi lainnya hanya tersedia melalui WMI (dan Anda mungkin harus menginstal beberapa perbaikan terbaru atau paket layanan untuk mendapatkannya di beberapa sistem):

Pastikan untuk menambahkan referensi dalam proyek Anda ke System.Management.dll Di .NET Core, ini tersedia (hanya untuk Windows) sebagai paket NuGet.

Prosesor Fisik:

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

Core:

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

Prosesor logis:

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

ATAU

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

Prosesor yang dikecualikan dari Windows:

Anda juga dapat menggunakan panggilan Windows API di setupapi.dll untuk menemukan prosesor yang telah dikecualikan dari Windows (misalnya melalui pengaturan boot) dan tidak terdeteksi menggunakan cara di atas. Kode di bawah ini memberikan jumlah total prosesor logis (saya belum dapat menemukan cara membedakan fisik dari prosesor logis) yang ada, termasuk yang telah dikecualikan dari 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: Benar, tapi saya berharap itu dalam format yang lebih bagus. Keterjangkauan cukup rendah ketika Anda harus membangun kueri string mentah.
Kevin Kibler

5
Pembuat Kode WMI akan membantu dengan penemuan nilai dan pembuatan kueri (bahkan dapat menghasilkan stubs di c # / vb.net).
StingyJack

4
Ada di System.Management.dll. Apakah Anda memasukkan referensi ke majelis itu dalam proyek Anda?
Kevin Kibler

2
Masalah kecil satu per satu dalam kode di atas. Karena deviceCountberbasis nol, jumlah inti harus berupa output seperti ini:Console.WriteLine("Number of cores: {0}", deviceCount + 1);
Francis Litterio

2
Tidakkah Anda menyebabkan masalah dengan tidak membuang objek dan pencari manajemen?
Benjamin

205
Environment.ProcessorCount

[Dokumentasi]


12
Sederhana sekali, sampai-sampai aku menangis. Terima kasih atas jawabannya!
MrGreggles

70
Ini memberikan jumlah prosesor logis, bukan jumlah core.
Kevin Kibler

8
@KevinKibler Dari pertanyaan, saya curiga OP tidak mengerti perbedaannya, dan jika Anda tidak tahu perbedaannya, ini mungkin yang Anda inginkan.
Glenn Maynard

1
Ini juga mengembalikan hitungan salah pada banyak sistem inti. Saya menjalankan dua prosesor inti dodeca dengan hyper-threading, yang memberi saya total 48 prosesor logis. Environment.ProcessorCountmenghasilkan 32.
Allen Clark Copeland Jr

1
@AlexanderMorou, ya ini akan gagal memberikan hasil yang akurat pada beberapa server multi-CPU. Ada perbaikan untuk ini, tetapi belum mengujinya.
TheLegendaryCopyCoder

35

Kueri WMI lambat, jadi cobalah Pilih hanya anggota yang diinginkan daripada menggunakan Pilih *.

Permintaan berikut membutuhkan waktu 3.4s:

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

Sementara yang ini membutuhkan 0,122:

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

1
Anda menjalankan sistem apa ini? Saya menggunakan beberapa "Pilih *" query dan tidak mengambil di mana saja dekat 3,4 detik, diuji pada ribuan komputer yang perangkat lunak saya ditempatkan di. Saya melakukan Select * karena saya mendapatkan beberapa properti dari objek. Namun, saya melakukannya sedikit berbeda: membuat ObjectQuery pada Select *; dapatkan ManagementObjectCollection; kemudian foreach ManagementObject di ManagementObjectCollection.
deegee

@deegee: Anda benar, permintaan itu sendiri tidak memakan waktu lebih lama dengan "Pilih *", hanya saja penguraian int di bawah ini lambat jika iterasi semua nilai yang dikembalikan bukan hanya NumberOfCores.
Aleix Mercader


10

Ini agak menarik untuk melihat bagaimana. NET mendapatkan ini secara internal untuk sedikitnya ... Ini "sesederhana" seperti di bawah ini:

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

Dari sumber .NET Framework

Anda juga bisa mendapatkannya dengan PInvoke aktifKernel32.dll

Kode berikut ini kurang lebih berasal dari SystemInfo.csdari sumber System.Web yang terletak di sini :

[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
Sudah mencoba ini, tetapi ia mengembalikan jumlah prosesor logis - yang merupakan hasil yang sama dengan memanggil Environment.ProcessorCount.
Bob Bryan

1

Salah satu opsi adalah membaca data dari registri. Artikel MSDN Pada Topik: http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.localmachine(v=vs.71).aspx )

Prosesor, saya yakin dapat ditemukan di sini, 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();
    }

Saya cukup yakin entri registri akan ada di sebagian besar sistem.

Meskipun saya akan membuang $ 0,02 saya di.


Ini akan memberikan sejumlah prosesor yang sudah tersedia di Environment.ProcessorCount, apakah ada cara serupa lainnya untuk mendapatkan jumlah core untuk setiap prosesor?
Armen

0

Program berikut mencetak inti logis dan fisik mesin 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
Pertanyaan ini ditandai .NET; kode Anda bukan .NET code.
Wai Ha Lee

-1

Saya mencari hal yang sama tetapi saya tidak ingin menginstal paket nuget atau servicepack, jadi saya menemukan solusi ini, sangat sederhana dan lurus ke depan, menggunakan diskusi ini , saya pikir akan sangat mudah untuk menjalankan perintah WMIC itu dan dapatkan nilai itu, berikut adalah kode C #. Anda hanya perlu menggunakan namespace System.Management (dan pasangan ruang nama standar lebih untuk proses dan sebagainya).

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
Tidak yakin mengapa Anda membuat kueri WMI sederhana sangat rumit. Memulai baris perintah WMI sebagai proses eksternal dan mem-parsing outputnya benar-benar tidak perlu. .NET memiliki dukungan bawaan untuk kueri WMI (System.Management.ManagementObjectSearcher), karena beberapa jawaban lain di sini sudah diilustrasikan. Juga, saya tidak tahu mengapa Anda berpikir paket nuget atau paket layanan akan diperlukan saat menggunakan dukungan WMI built-in .NET bukannya wmic.exe ...
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.