Làm cách nào để tìm Số lượng CPU thông qua .NET / C #?


317

Có cách nào thông qua .NET / C # để tìm ra số lượng lõi CPU không?

PS Đây là một câu hỏi mã thẳng, không phải là "Tôi có nên sử dụng đa luồng không?" câu hỏi :-)


7
Bạn có cần biết có bao nhiêu lõi hay có bao nhiêu bộ xử lý logic không? Đối với việc chỉ chạy nhiều luồng, có thể là đủ, nhưng có những kịch bản mà sự khác biệt có thể quan trọng.
Kevin Kibler

Có một cách mới hơn để làm điều này?
MoonKnight

Câu trả lời:


477

Có một số thông tin khác nhau liên quan đến bộ xử lý mà bạn có thể nhận được:

  1. Số lượng bộ xử lý vật lý
  2. Số lượng lõi
  3. Số lượng bộ xử lý logic.

Những điều này có thể khác nhau; trong trường hợp máy có 2 bộ xử lý siêu phân luồng kép, có 2 bộ xử lý vật lý, 4 lõi và 8 bộ xử lý logic.

Số lượng bộ xử lý logic có sẵn thông qua lớp Môi trường , nhưng thông tin khác chỉ có sẵn thông qua WMI (và bạn có thể phải cài đặt một số hotfix hoặc gói dịch vụ để có được nó trên một số hệ thống):

Đảm bảo thêm một tham chiếu trong dự án của bạn vào System.Man Quản lý Trong .NET Core, điều này có sẵn (chỉ dành cho Windows) dưới dạng gói NuGet.

Bộ xử lý vật lý:

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

Lõi:

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

Bộ xử lý logic:

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

HOẶC LÀ

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

Bộ xử lý loại trừ khỏi Windows:

Bạn cũng có thể sử dụng các lệnh gọi API của Windows trong setupapi.dll để khám phá các bộ xử lý đã bị loại trừ khỏi Windows (ví dụ: thông qua cài đặt khởi động) và không thể phát hiện được bằng các phương tiện trên. Đoạn mã dưới đây cung cấp tổng số bộ xử lý logic (tôi chưa thể tìm ra cách phân biệt vật lý với bộ xử lý logic) tồn tại, bao gồm cả những bộ xử lý đã bị loại trừ khỏi 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: Đúng, nhưng tôi ước nó ở định dạng đẹp hơn. Khả năng khám phá là khá thấp khi bạn phải xây dựng các truy vấn chuỗi thô.
Kevin Kibler

5
WMI Code Creator sẽ giúp phát hiện giá trị và tạo truy vấn (thậm chí nó có thể tạo ra các sơ khai trong c # / vb.net).
StingyJack

4
Nó nằm trong System.Manloyment.dll. Bạn đã bao gồm một tài liệu tham khảo cho hội đồng đó trong dự án của bạn?
Kevin Kibler

2
Vấn đề nhỏ từng chút một trong đoạn mã trên. Vì deviceCountlà không dựa trên, nên số lượng cốt lõi sẽ là đầu ra như thế này:Console.WriteLine("Number of cores: {0}", deviceCount + 1);
Francis Litterio

2
Bạn không gây ra vấn đề bằng cách không xử lý các đối tượng quản lý và người tìm kiếm?
Benjamin

205
Environment.ProcessorCount

[Tài liệu]


12
Điều đó thật đơn giản, tôi gần như rơi nước mắt. Thx đã trả lời!
MrGreggles

70
Điều này cho số lượng bộ xử lý logic, không phải số lượng lõi.
Kevin Kibler

8
@KevinKibler Từ câu hỏi, tôi nghi ngờ OP không hiểu sự khác biệt và nếu bạn không biết sự khác biệt thì đây có lẽ là điều bạn muốn.
Glenn Maynard

1
Điều này cũng trả về số lượng sai trên nhiều hệ thống cốt lõi. Tôi đang chạy hai bộ xử lý lõi dodeca với siêu phân luồng, cung cấp cho tôi tổng cộng 48 bộ xử lý logic. Environment.ProcessorCountmang lại 32.
Allen Clark Copeland Jr

1
@AlexanderMorou, vâng, điều này sẽ không cung cấp kết quả chính xác trên một số máy chủ nhiều CPU. Có một sửa chữa cho điều này, nhưng chưa thử nghiệm nó.
TheLegendaryCopyCoder

35

Các truy vấn WMI chậm, vì vậy hãy cố gắng chỉ chọn các thành viên mong muốn thay vì sử dụng Chọn *.

Truy vấn sau đây mất 3,4 giây:

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

Trong khi cái này mất 0.122s:

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

1
Bạn đang chạy hệ thống này trên hệ thống nào? Tôi sử dụng nhiều "Select *" truy vấn và nó không mất bất cứ nơi nào gần 3,4 giây, thử nghiệm trên hàng ngàn máy tính mà phần mềm của tôi được triển khai trên. Tôi thực hiện Chọn * vì tôi nhận được nhiều thuộc tính từ đối tượng. Tuy nhiên, tôi làm điều đó hơi khác một chút: tạo ObjectQuery trên Chọn *; nhận được ManagementObjectCollection; sau đó tìm kiếm ManagementObject trong ManagementObjectCollection.
deegee

@deegee: bạn đã đúng, bản thân truy vấn không mất nhiều thời gian hơn với "Chọn *", chỉ là việc phân tích cú pháp int bên dưới bị chậm nếu lặp lại tất cả các giá trị được trả về thay vì chỉ NumberOfCores.
Aleix Mercader


10

Thật thú vị khi xem .NET làm thế nào để nói điều này trong nội bộ để nói rằng ít nhất ... Nó "đơn giản" như dưới đây:

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

Từ nguồn .NET Framework

Bạn cũng có thể tải nó với PInvoke trênKernel32.dll

Đoạn mã sau đến SystemInfo.cstừ nguồn System.Web được đặt ở đây :

[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
Đã thử điều này, nhưng nó trả về số lượng bộ xử lý logic - đó là kết quả tương tự như khi gọi Môi trường.ProcessorCount.
Bob Bryan

1

Một lựa chọn sẽ là đọc dữ liệu từ sổ đăng ký. Bài viết về MSDN về chủ đề: http://msdn.microsoft.com/en-us/l Library / microsoft.win32.registry.localmachine (v = vs.71 ) .aspx )

Các bộ xử lý, tôi tin rằng có thể được đặt ở đây, 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();
    }

Tôi chắc chắn chắc chắn rằng mục đăng ký sẽ có mặt trên hầu hết các hệ thống.

Mặc dù tôi sẽ ném 0,02 đô la của tôi vào.


Điều này sẽ đưa ra số lượng bộ xử lý đã có sẵn trong Môi trường.ProcessorCount, có cách nào tương tự khác để lấy số lõi cho mỗi bộ xử lý không?
Armen

0

Chương trình sau đây in các lõi logic và vật lý của máy 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
Câu hỏi này được gắn thẻ .NET; mã của bạn không phải là mã .NET.
Wai Ha Lee

-1

Tôi đang tìm kiếm điều tương tự nhưng tôi không muốn cài đặt bất kỳ nuget hoặc gói dịch vụ nào, vì vậy tôi đã tìm thấy giải pháp này, nó khá đơn giản và dễ dàng, sử dụng cuộc thảo luận này , tôi nghĩ rằng sẽ rất dễ dàng để chạy lệnh WMIC đó và nhận giá trị đó, đây là mã C #. Bạn chỉ cần sử dụng không gian tên System.Man Quản lý (và thêm vài không gian tên tiêu chuẩn cho quy trình, v.v.).

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
Không chắc chắn tại sao bạn thực hiện một truy vấn WMI đơn giản lại phức tạp như vậy. Bắt đầu dòng lệnh WMI như một quy trình bên ngoài và phân tích cú pháp đầu ra của nó là thực sự không cần thiết. .NET có hỗ trợ tích hợp cho các truy vấn WMI (System.Man Quản lý. Quản lýObjectSearcher), như một số câu trả lời khác ở đây đã được minh họa. Ngoài ra, tôi không biết lý do tại sao bạn nghĩ các gói nuget hoặc gói dịch vụ sẽ được yêu cầu khi sử dụng hỗ trợ WMI tích hợp của .NET thay vì wmic.exe ...
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.