如何通过.NET / C#findCPU核心的数量?
有没有办法通过.NET / C#来找出CPU核心的数量?
PS这是一个直接的代码问题,而不是“我应该使用multithreading?” 题! 🙂
有几个不同的处理器信息可以得到:
- 物理处理器的数量
- 核心数量
- 逻辑处理器的数量。
这些都可以不同; 在具有2个双核超线程处理器的机器的情况下,有2个物理处理器,4个核心和8个逻辑处理器。
逻辑处理器的数量可以通过Environment类获得,但其他信息只能通过WMI获得 (您可能需要安装一些修补程序或服务包才能在某些系统上获得):
确保在项目中添加一个引用到System.Management.dll
物理处理器:
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 - 1; 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, }
Environment.ProcessorCount
[文档]
WMI查询很慢,所以请尝试仅select所需的成员,而不是使用Select *。
以下查询需要3.4s:
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())
虽然这一个需要0.122s:
foreach (var item in new System.Management.ManagementObjectSearcher("Select NumberOfCores from Win32_Processor").Get())
Environment.ProcessorCount应该为您提供本地机器上的核心数量。
看看.NET如何从内部得到这个至less可以说是相当有趣的。这是“简单的”,如下所示:
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; } } } }
从.NET Framework源代码
您也可以通过Kernel32.dll
上的PInvoke获取它
下面的代码或多或less来自System.Web源代码中的SystemInfo.cs
:
[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 { 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; } }
一种select是从registry中读取数据。 MSDN文章主题: http : //msdn.microsoft.com/en-us/library/microsoft.win32.registry.localmachine (v= vs.71 ) .aspx )
处理器,我相信可以在这里find,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(); }
我相当确定registry项将在大多数系统上。
虽然我会把我的0.02美元。
以下程序打印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 */
我正在寻找同样的东西,但我不想安装任何nuget或servicepack,所以我find了这个解决scheme,这是非常简单和直接的,使用这个讨论,我认为这将是如此容易运行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();