.NET Core下如何获取物理CPU核心数(而非逻辑超线程核心数)
好问题!确实在你提到的这类计算密集型场景——比如线程竞争私有缓存、IPC高到超线程的吞吐量提升抵不上开销时,物理核心数才是决定最优并行线程数的关键,System.Environment.ProcessorCount返回的逻辑核心数反而会误导我们。下面给你几个跨平台的可靠实现方案:
方案一:手动实现跨平台原生调用/文件读取
我们可以针对不同操作系统,分别调用对应的原生接口或读取系统文件来获取物理核心数,这不需要依赖第三方库,完全自主可控:
代码示例
using System; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; public static class PhysicalCoreHelper { public static int GetPhysicalCoreCount() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // Windows平台:使用WMI查询物理核心数 using var searcher = new System.Management.ManagementObjectSearcher("SELECT NumberOfCores FROM Win32_Processor"); using var collection = searcher.Get(); return collection.Cast<System.Management.ManagementObject>() .Sum(mo => (uint)mo["NumberOfCores"]); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { // Linux平台:读取/proc/cpuinfo统计唯一物理核心 var cpuInfo = System.IO.File.ReadAllText("/proc/cpuinfo"); var physicalCoreIds = cpuInfo.Split('\n') .Where(line => line.StartsWith("physical id") || line.StartsWith("core id")) .Select(line => line.Split(':')[1].Trim()) .ToArray(); // 每两个一组(physical id + core id)作为唯一物理核心标识 var uniqueCores = new System.Collections.Generic.HashSet<string>(); for (int i = 0; i < physicalCoreIds.Length; i += 2) { uniqueCores.Add($"{physicalCoreIds[i]}-{physicalCoreIds[i+1]}"); } return uniqueCores.Count; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { // macOS平台:调用sysctl命令获取物理核心数 var process = new Process { StartInfo = new ProcessStartInfo { FileName = "/usr/sbin/sysctl", Arguments = "-n machdep.cpu.core_count", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true } }; process.Start(); var output = process.StandardOutput.ReadToEnd().Trim(); process.WaitForExit(); return int.Parse(output); } // 未知平台 fallback 到逻辑核心数 return Environment.ProcessorCount; } }
注意:Windows平台需要安装System.Management NuGet包;Linux平台需要确保程序有权限读取/proc/cpuinfo(通常默认就有)。
方案二:使用第三方跨平台硬件信息库
如果你不想手动处理各平台差异,可以使用成熟的第三方库,比如Hardware.Info(NuGet可安装),它已经封装了跨平台的硬件信息获取逻辑,包括物理核心数:
代码示例
using Hardware.Info; public static int GetPhysicalCoreCountWithLibrary() { var hardwareInfo = new HardwareInfo.HardwareInfo(); hardwareInfo.RefreshCPUList(); return hardwareInfo.CpuList.Sum(cpu => cpu.NumberOfCores); }
这个库支持Windows、Linux、macOS等主流平台,底层已经处理了不同架构的细节(比如你提到的AMD推土机系列CMP架构,它也能正确识别物理核心相关信息,你可以根据工作负载再调整是否合并共享单元的核心)。
关于你提到的“计时推测法”
这种方法确实不推荐——它受当前系统负载、缓存预热状态、其他进程占用等因素影响极大,结果波动非常大,而且会额外消耗计算资源,在生产环境中完全不实用。
补充说明
针对你提到的AMD推土机系列这类特殊架构(多个整数核心共享FPU/SIMD单元),你可以在获取物理核心数后,根据具体工作负载做调整:比如如果你的任务是整数计算为主,那可以按物理核心数的2倍来设置线程数;如果是浮点/SIMD密集型任务,那还是按物理核心数设置更优。
内容的提问来源于stack exchange,提问作者Hessi9

