Existe-t-il un moyen via .NET / C # de connaître le nombre de cœurs de processeur?
PS Ceci est une question de code simple, pas un “Dois-je utiliser le multi-threading?” question! 🙂
Vous pouvez obtenir plusieurs informations sur les processeurs:
Tout cela peut être différent. Dans le cas d’une machine dotée de deux processeurs compatibles Hyper-Threading à deux cœurs, il existe deux processeurs physiques, quatre cœurs et huit processeurs logiques.
Le nombre de processeurs logiques est disponible via la classe Environment , mais les autres informations sont uniquement disponibles via WMI (et vous devrez peut-être installer des correctifs ou des service packs sur certains systèmes):
Veillez à append une référence dans votre projet à System.Management.dll
Processeurs Physiques:
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_ComputerSystem").Get()) { Console.WriteLine("Number Of Physical Processors: {0} ", item["NumberOfProcessors"]); }
Noyaux:
int coreCount = 0; foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get()) { coreCount += int.Parse(item["NumberOfCores"].ToSsortingng()); } Console.WriteLine("Number Of Cores: {0}", coreCount);
Processeurs logiques:
Console.WriteLine("Number Of Logical Processors: {0}", Environment.ProcessorCount);
OU
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_ComputerSystem").Get()) { Console.WriteLine("Number Of Logical Processors: {0}", item["NumberOfLogicalProcessors"]); }
Processeurs exclus de Windows:
Vous pouvez également utiliser les appels API Windows dans setupapi.dll pour découvrir les processeurs exclus de Windows (par exemple, via les parameters de démarrage) et qui ne sont pas détectables à l’aide des moyens ci-dessus. Le code ci-dessous indique le nombre total de processeurs logiques (je n’ai pas réussi à différencier les processeurs physiques des processeurs logiques), y compris ceux qui ont été exclus de Windows:
static void Main(ssortingng[] 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)]Ssortingng 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
[Documentation]
Les requêtes WMI sont lentes, alors essayez de sélectionner uniquement les membres souhaités au lieu d’utiliser Select *.
La requête suivante prend 3.4s:
foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())
Alors que celui-ci prend 0.122s:
foreach (var item in new System.Management.ManagementObjectSearcher("Select NumberOfCores from Win32_Processor").Get())
Environment.ProcessorCount devrait vous donner le nombre de cœurs sur la machine locale.
C’est assez intéressant de voir comment .NET obtient cela en interne pour le moins qu’on puisse dire … C’est aussi simple que ci-dessous:
namespace System.Threading { using System; using System.Runtime.ComstackrServices; 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; } } } }
Vous pouvez également l’obtenir avec PInvoke sur Kernel32.dll
Le code suivant provient plus ou moins de SystemInfo.cs
de la source System.Web située ici :
[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; } }
La méthode la plus simple = Environment.ProcessorCount
Exemple de la propriété Environment.ProcessorCount
using System; class Sample { public static void Main() { Console.WriteLine("The number of processors " + "on this computer is {0}.", Environment.ProcessorCount); } }
Une option serait de lire les données du registre. Article MSDN sur la rubrique: http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.localmachine(v=vs.71).aspx )
Je pense que les processeurs peuvent être localisés ici, HKEY_LOCAL_MACHINE \ HARDWARE \ DESCRIPTION \ System \ CentralProcessor
private void determineNumberOfProcessCores() { RegistryKey rk = Registry.LocalMachine; Ssortingng[] subKeys = rk.OpenSubKey("HARDWARE").OpenSubKey("DESCRIPTION").OpenSubKey("System").OpenSubKey("CentralProcessor").GetSubKeyNames(); textBox1.Text = "Total number of cores:" + subKeys.Length.ToSsortingng(); }
Je suis raisonnablement sûr que l’entrée de registre sera là sur la plupart des systèmes.
Bien que je jette mon 0,02 $ dans
Le programme suivant imprime les cœurs logiques et physiques d’une machine Windows.
#define STRICT #include "stdafx.h" #include #include #include template T *AdvanceBytes(T *p, SIZE_T cb) { return reinterpret_cast(reinterpret_cast(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 (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 */
Je cherchais la même chose mais je ne veux pas installer de nuget ou de servicepack, alors j’ai trouvé cette solution, c’est simple et direct, en utilisant cette discussion, j’ai pensé qu’il serait si facile d’exécuter cette commande WMIC et obtenez cette valeur, voici le code C #. Il vous suffit d’utiliser l’espace de noms System.Management (et de coupler d’autres espaces de noms standard pour le processus, etc.).
ssortingng fileName = Path.Combine(Environment.SystemDirectory, "wbem", "wmic.exe"); ssortingng 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();