在C#中监控特定程序的CPU占用率,本质上是读取系统为该进程记录的处理器时间,并结合采样间隔进行换算。下面介绍几种常见且稳定的实现方式。

使用PerformanceCounter获取进程CPU占用率
PerformanceCounter是.NET提供的性能计数器封装,能够直接读取系统已有的性能数据。以下代码演示如何获取指定进程名的CPU占用率:
using System;
using System.Diagnostics;
class CpuMonitor
{
static void Main()
{
// 进程名不包含.exe后缀
string processName = "notepad";
using (PerformanceCounter cpuCounter = new PerformanceCounter(
"Process", "% Processor Time", processName, true))
{
// 第一次读取通常会返回0,需先调用一次
cpuCounter.NextValue();
System.Threading.Thread.Sleep(1000);
float cpuUsage = cpuCounter.NextValue();
// 多核机器上该值可能超过100,需除以逻辑核心数
int coreCount = Environment.ProcessorCount;
Console.WriteLine($"CPU占用率: {cpuUsage / coreCount:F2}%");
}
}
}
注意事项
- 进程名应使用任务管理器中不含扩展名的名称。
- 多核环境下计数器返回的是所有核心时间总和,需除以核心数。
- 首次调用NextValue返回0,必须间隔一小段时间再取第二次。
通过Process类计算CPU时间差
如果不想依赖性能计数器名称,也可以用Process类自己采样两次TotalProcessorTime,再除以经过的真实时间:
using System;
using System.Diagnostics;
class ProcessCpuSampler
{
static void Main()
{
Process target = Process.GetProcessesByName("notepad")[0];
TimeSpan startCpu = target.TotalProcessorTime;
DateTime startTime = DateTime.Now;
System.Threading.Thread.Sleep(1000);
target.Refresh();
TimeSpan endCpu = target.TotalProcessorTime;
double cpuUsedMs = (endCpu - startCpu).TotalMilliseconds;
double totalMs = (DateTime.Now - startTime).TotalMilliseconds;
int cores = Environment.ProcessorCount;
double usage = (cpuUsedMs / (totalMs * cores)) * 100;
Console.WriteLine($"计算得到的CPU占用率: {usage:F2}%");
}
}
两种方案对比
| 方式 | 优点 | 缺点 |
|---|---|---|
| PerformanceCounter | 系统级准确,代码简单 | 依赖计数器名称,多语言系统可能不一致 |
| Process时间差 | 不依赖计数器,兼容性好 | 需自己处理采样和时间换算 |
监控多个进程的简单封装
实际项目中常需要持续监控,可以用一个字典保存上一次采样数据:
using System;
using System.Collections.Generic;
using System.Diagnostics;
class MultiProcessMonitor
{
static Dictionary<int, (TimeSpan cpu, DateTime time)> last = new();
static double GetUsage(Process p)
{
p.Refresh();
var now = DateTime.Now;
var snap = (p.TotalProcessorTime, now);
if (last.TryGetValue(p.Id, out var prev))
{
double ms = (snap.cpu - prev.cpu).TotalMilliseconds;
double span = (now - prev.time).TotalMilliseconds;
last[p.Id] = snap;
return ms / (span * Environment.ProcessorCount) * 100;
}
last[p.Id] = snap;
return 0;
}
}
通过上述方法,开发者可以在C#中灵活获取并监控任意进程的CPU占用情况,从而快速发现异常消耗资源的程序。