You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux系统下用C#获取当前CPU使用率的技术问题求助

解决Linux下总CPU使用率计算问题

最优方案:直接读取/proc/stat文件

Linux系统的CPU统计信息原生存储在/proc/stat中,这是最高效、无权限问题的获取方式,完全避开Docker进程的权限限制。

原理

/proc/stat的第一行cpu记录了所有逻辑CPU的累计时间(单位:jiffies,通常1jiffy=1/100秒),包含用户态、内核态、空闲等多个时间字段。总CPU使用率通过两次读取的时间差值计算:

总CPU时间 = user + nice + system + idle + iowait + irq + softirq + ...
空闲时间差 = 当前idle - 上次idle
总时间差 = 当前总CPU时间 - 上次总CPU时间
使用率 = (1 - 空闲时间差 / 总时间差) * 100

C#实现代码

using System;
using System.IO;
using System.Threading.Tasks;

public class CpuUsageCalculator
{
    private (ulong total, ulong idle) _prevCpuStats;
    private readonly int _cpuCount = Environment.ProcessorCount; // 获取逻辑CPU核心数

    public CpuUsageCalculator()
    {
        // 初始化首次统计数据
        _prevCpuStats = ReadCpuStats();
    }

    public double GetTotalCpuUsage()
    {
        var currentStats = ReadCpuStats();
        var totalDiff = currentStats.total - _prevCpuStats.total;
        var idleDiff = currentStats.idle - _prevCpuStats.idle;

        if (totalDiff == 0)
            return 0;

        var usage = (1 - (double)idleDiff / totalDiff) * 100;
        _prevCpuStats = currentStats;
        return Math.Round(usage, 2);
    }

    private (ulong total, ulong idle) ReadCpuStats()
    {
        var statLine = File.ReadAllLines("/proc/stat")[0];
        var parts = statLine.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);

        ulong total = 0;
        ulong idle = 0;

        // parts[0]是"cpu",从parts[1]开始是各时间字段
        for (int i = 1; i < parts.Length; i++)
        {
            if (!ulong.TryParse(parts[i], out var value))
                continue;

            total += value;
            if (i == 4) // 第5个字段是idle(索引从1开始)
                idle = value;
        }

        return (total, idle);
    }
}

// 使用示例:每10秒上报一次
public class UsageReporter
{
    private readonly CpuUsageCalculator _cpuCalc = new CpuUsageCalculator();

    public async Task StartReporting()
    {
        while (true)
        {
            await Task.Delay(10000);
            var cpuUsage = _cpuCalc.GetTotalCpuUsage();
            Console.WriteLine($"当前总CPU使用率:{cpuUsage}%");
            // 在这里执行上报逻辑
        }
    }
}

修正你第一种方法的问题

你用node_exporter数据计算时数值异常,是因为两个错误:

  1. 公式逻辑反了:你计算的是空闲率的倍数,而非使用率
  2. 未除以逻辑CPU核心数:node_cpu_seconds_total是每个逻辑核心的时间总和,总可用时间应为delta.TotalSeconds * 逻辑核心数

修正后的代码:

// 先获取逻辑CPU核心数
int cpuCount = Environment.ProcessorCount;
TimeSpan delta = DateTime.Now - _lastTimeBuildReport;

var idleCurrent = currentExporterDic["node_cpu_seconds_total"].GetSum("idle");
var idlePrev = _previousExporterDic["node_cpu_seconds_total"].GetSum("idle");
var idleDiff = idleCurrent - idlePrev;

// 计算实际使用率
double cpuLoad = 100 * (1 - idleDiff / (cpuCount * delta.TotalSeconds));
// 确保数值在0-100之间
cpuLoad = Math.Clamp(cpuLoad, 0, 100);

为什么第二种方法不可行

你用Process.GetProcesses()遍历所有进程的方式有致命问题:

  • 无法访问Docker容器内的特权进程,必然抛出权限错误
  • 效率极低:每个进程都要等待totalMsPassed时间,遍历所有进程会导致耗时成倍增加
  • 进程可能在遍历过程中退出,引发异常

这种方法完全不适用于Linux环境下的系统总CPU使用率统计。

内容的提问来源于stack exchange,提问作者Yuki1112

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 11:40:23