C#获取Windows磁盘% Disk Time百分比使用率返回0值问题排查
问题根因
你代码始终返回0是三个核心问题导致的:
- 取值字段错误:
NextSample().BaseValue是性能计数器的原始基准值,不是% Disk Time计算完成后的百分比结果。% Disk Time属于基于时间间隔计算的平均计数器,必须通过两次采样的差值才能算出有效结果。 - 计数器实例反复重建:你每次循环都重新
new PerformanceCounter,新实例第一次调用采样方法时只会返回初始基准值0,没有保留前一次采样的历史数据,永远无法算出间隔区间的统计值。 - 实例匹配逻辑不可靠:直接通过盘符首字母Contains匹配很容易匹配到错误实例,比如多磁盘环境下
0 C:、1 D:这类带数字前缀的实例名,容易误匹配到其他磁盘,甚至匹配到不存在的无效实例。
修正方案
- 提前在循环外初始化所有需要的
PerformanceCounter实例,全局复用,不要在每次轮询时新建。初始化完成后先调用一次NextValue()完成首次基准采样。 - 取值时直接调用计数器的
NextValue()方法,两次调用间隔1秒以上,第二次及以后返回的结果就是对应时间区间的磁盘时间百分比,不要取BaseValue字段。 - 修正实例匹配规则:固定磁盘的PhysicalDisk实例名格式为
X:(盘符+冒号),匹配时精确匹配后缀,同时过滤掉_Total汇总实例、光驱/网络盘/可移动盘这类无有效统计值的驱动器。 - 如果修正后所有计数器仍然返回0,以管理员身份打开命令提示符执行
lodctr /r修复系统损坏的性能计数器库即可。
修正后的可运行代码如下:
using System.Diagnostics; using System.IO; // 初始化物理磁盘性能计数器分类 var diskCategory = new PerformanceCounterCategory("PhysicalDisk"); var diskCounters = new List<PerformanceCounter>(); // 提前枚举所有本地固定磁盘,初始化对应计数器 foreach (var drive in DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.Fixed)) { var driveLetter = drive.Name[0]; var targetInstance = diskCategory.GetInstanceNames() .FirstOrDefault(ins => ins.Equals($"{driveLetter}:", StringComparison.OrdinalIgnoreCase)); if (!string.IsNullOrEmpty(targetInstance)) { var counter = new PerformanceCounter("PhysicalDisk", "% Disk Time", targetInstance, true); // 首次调用完成基准采样,丢弃初始0值 _ = counter.NextValue(); diskCounters.Add(counter); } } // 轮询取值 while (true) { foreach (var counter in diskCounters) { var diskTime = counter.NextValue(); Console.WriteLine($"磁盘 {counter.InstanceName} 磁盘时间占比:{diskTime:F2}%"); } Thread.Sleep(1000); }
补充说明:Windows的
% Disk Time计数器设计上允许数值超过100%,这是因为统计时会累加并发IO的耗时,代表磁盘存在IO队列堆积,属于正常现象,不是取值错误。
内容的提问来源于stack exchange,提问作者HermanChris22
相关产品推荐
相关产品推荐

