.NET Core 8 Web API获取与任务管理器一致的CPU、RAM使用率
.NET Core 8 Web API 准确获取CPU和RAM使用率(匹配任务管理器数值)
问题
在.NET Core 8 Web API中尝试获取某一时刻的CPU和RAM使用率百分比,目前RAM数值与任务管理器接近,但CPU使用率偏差较大。原有代码如下:
public async Task<void> getCpuUsageData() { try { var CpuThreadSleepTime = _appSettings.ThreadSleepTimeForCPU; // CpuThreadSleepTime - 30000 var RamThreadSleepTime = _appSettings.ThreadSleepTimeForRAM; // RamThreadSleepTime - 30000 var totalMemory = GetTotalPhysicalMemory(); var totalCpu = GetTotalCpu(); var ramCounter = new PerformanceCounter("Memory", "Available MBytes"); var availableMemory = ramCounter.NextValue(); var usedMemory = totalMemory - availableMemory; var usedMemoryPercentage = (usedMemory / totalMemory) * 100; var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); cpuCounter.NextValue(); Thread.Sleep(CpuThreadSleepTime); var cpuUsagePercentage = cpuCounter.NextValue(); var usedCpu = totalCpu - cpuUsagePercentage; var usedCpuPercentage = (usedCpu / totalCpu) * 100; Console.WriteLine("Used Ram Percentage : " + usedMemoryPercentage); Console.WriteLine("Used CPU Percentage : " + usedCpuPercentage); } catch (Exception ex) { throw ex; } } public float GetTotalPhysicalMemory() { try { float totalMemory = 0; ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem"); foreach (ManagementObject mo in searcher.Get()) { totalMemory = Convert.ToSingle(mo["TotalPhysicalMemory"]) / (1024 * 1024); // Convert bytes to MB } return totalMemory; } catch (Exception ex) { throw ex; } } public float GetTotalCpu() { try { int totalCpu = 0; ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT NumberOfLogicalProcessors FROM Win32_Processor"); foreach (ManagementObject mo in searcher.Get()) { totalCpu += Convert.ToInt32(mo["NumberOfLogicalProcessors"]); } return (float)totalCpu; } catch (Exception ex) { throw ex; } }
问题分析
- CPU计算逻辑错误:
Processor计数器的% Processor Time(_Total实例)返回的就是所有逻辑核心的总使用率百分比(范围0-100),不需要用逻辑核心数做减法运算,原有代码的usedCpu = totalCpu - cpuUsagePercentage完全不符合逻辑。 - 采样间隔过长:任务管理器的CPU使用率是取最近1-2秒的平均值,原有代码休眠30秒会导致采样的是30秒前的使用率,偏差极大。
- 异步方法使用不当:
async Task<void>应改为async Task,且用await Task.Delay()替代Thread.Sleep()避免阻塞线程池线程。 - 内存计算可优化:可以直接使用
Memory计数器的% Committed Bytes In Use获取内存使用率,无需手动计算。
修正后的代码
using System.Diagnostics; using System.Management; public async Task GetSystemUsageData() { try { // 内存使用率获取(与任务管理器匹配) using var ramCounter = new PerformanceCounter("Memory", "% Committed Bytes In Use"); var usedMemoryPercentage = ramCounter.NextValue(); // 首次获取可能为0,需等待短时间再取一次 await Task.Delay(100); usedMemoryPercentage = ramCounter.NextValue(); // CPU使用率获取(与任务管理器匹配) using var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); // 首次调用NextValue()返回0,需触发采样 cpuCounter.NextValue(); // 等待100ms获取有效采样(匹配任务管理器的短周期平均) await Task.Delay(100); var usedCpuPercentage = cpuCounter.NextValue(); // 输出结果 Console.WriteLine($"Used Ram Percentage : {Math.Round(usedMemoryPercentage, 1)}%"); Console.WriteLine($"Used CPU Percentage : {Math.Round(usedCpuPercentage, 1)}%"); } catch (Exception ex) { // 建议添加日志而非直接抛出,此处保留原有逻辑 throw ex; } } // 如需获取总内存大小,可保留此方法(可选) public float GetTotalPhysicalMemory() { using var searcher = new ManagementObjectSearcher("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem"); foreach (ManagementObject mo in searcher.Get()) { return Convert.ToSingle(mo["TotalPhysicalMemory"]) / (1024 * 1024 * 1024); // 转换为GB更直观 } return 0; }
关键说明
- CPU采样逻辑:
% Processor Time的_Total实例直接返回总CPU使用率,无需额外计算。两次NextValue()间隔100ms,符合任务管理器的采样周期,数值会高度匹配。 - 内存采样:
% Committed Bytes In Use直接对应任务管理器中“内存”选项卡的“已提交”百分比,和任务管理器显示一致。 - 资源释放:使用
using语句自动释放PerformanceCounter和ManagementObjectSearcher资源,避免内存泄漏。 - 异步优化:用
await Task.Delay()替代Thread.Sleep(),不会阻塞Web API的线程池线程,更符合异步编程规范。
内容的提问来源于stack exchange,提问作者Selaka Nanayakkara
相关产品推荐
相关产品推荐

