潮流有货 2025-11-16 18:10 采纳率: 98.5%
浏览 1
已采纳

如何在Linux中实时打印CPU使用率?

如何在Linux中实时监控并打印CPU使用率?常见问题是如何从 `/proc/stat` 获取原始CPU时间数据并准确计算使用率。由于该文件仅提供自系统启动以来的累计CPU时间(用户、系统、空闲等),需通过两次采样间隔内的差值来计算实际使用率。难点在于解析字段、处理多核CPU以及避免短时间高频采样的精度误差。如何用Shell或Python实现高效、低开销的实时更新,同时保持输出清晰可读,是实际应用中的典型挑战。
  • 写回答

1条回答 默认 最新

  • 白萝卜道士 2025-11-16 18:30
    关注

    一、Linux中实时监控CPU使用率的原理与实现路径

    在Linux系统中,/proc/stat 文件是获取CPU时间统计的核心接口。该文件第一行为全局CPU汇总数据,后续每行对应一个逻辑CPU核心(如 cpu0, cpu1...)。每一行包含多个字段,表示自系统启动以来累计的节拍数(jiffies),主要字段包括:

    • user:用户态执行时间
    • nice:低优先级用户态执行时间
    • system:内核态执行时间
    • idle:空闲时间
    • iowait:等待I/O完成的时间
    • irq:处理硬件中断时间
    • softirq:处理软中断时间

    由于这些值为累计值,必须通过两次采样之间的差值来计算实际使用率。公式如下:

    总时间 = user + nice + system + idle + iowait + irq + softirq
    使用率 = (总时间 - 空闲时间) / 总时间 × 100%
        

    二、Shell脚本实现基础版本的CPU监控

    以下是一个基于Shell的简单实现,每秒采样一次并输出整体CPU使用率:

    #!/bin/bash
    
    get_cpu_times() {
        cat /proc/stat | grep '^cpu ' | awk '{print $2+$3+$4+$5+$6+$7+$8, $5}'
    }
    
    read -r total1 idle1 < <(get_cpu_times)
    while true; do
        sleep 1
        read -r total2 idle2 < <(get_cpu_times)
        
        delta_total=$((total2 - total1))
        delta_idle=$((idle2 - idle1))
    
        if [ $delta_total -gt 0 ]; then
            usage=$((100 * (delta_total - delta_idle) / delta_total))
            printf "CPU Usage: %d%%\n" $usage
        fi
    
        total1=$total2
        idle1=$idle2
    done
        

    此方法适用于快速调试和轻量级部署,但难以扩展至多核分析或高精度场景。

    三、Python进阶实现:支持多核与动态刷新

    Python提供了更灵活的数据结构与可读性优势,适合构建生产级监控工具。以下代码展示如何解析所有CPU核心并实时打印使用情况:

    import time
    import os
    
    def read_cpu_stats():
        with open('/proc/stat', 'r') as f:
            lines = f.readlines()
        cpus = {}
        for line in lines:
            if line.startswith('cpu'):
                parts = line.strip().split()
                cpu_name = parts[0]
                values = list(map(int, parts[1:]))
                total = sum(values)
                idle = values[3] + values[4]  # idle + iowait 被视为非工作时间
                cpus[cpu_name] = {'total': total, 'idle': idle}
        return cpus
    
    def calc_usage(prev, curr):
        dt_total = curr['total'] - prev['total']
        dt_idle = curr['idle'] - prev['idle']
        if dt_total == 0:
            return 0.0
        return round((dt_total - dt_idle) / dt_total * 100, 2)
    
    # 主循环
    prev_stats = read_cpu_stats()
    try:
        while True:
            time.sleep(1)
            curr_stats = read_cpu_stats()
            print("\033[H\033[J", end="")  # 清屏
            print(f"{'CPU':<8} {'Usage (%)':<12}")
            print("-" * 20)
            for cpu in sorted(curr_stats.keys()):
                if cpu == 'cpu': continue  # 跳过总和行用于单独显示
                usage = calc_usage(prev_stats[cpu], curr_stats[cpu])
                color = "\033[32m" if usage < 50 else "\033[33m" if usage < 80 else "\033[31m"
                reset = "\033[0m"
                bar = '█' * int(usage // 5)
                print(f"{cpu:<8} {color}{usage:>6.2f}%{reset} |{bar:<20}|")
            prev_stats = curr_stats
    except KeyboardInterrupt:
        print("\nMonitoring stopped.")
        

    四、性能优化与精度控制策略

    高频采样可能导致数据抖动或资源浪费。以下是关键优化建议:

    问题原因解决方案
    短间隔采样误差大时间差太小导致除零或波动设置最小采样间隔(≥0.5s)
    多核处理复杂需分别跟踪每个cpuX行使用字典结构索引各核状态
    输出闪烁影响可读性频繁清屏造成视觉跳跃采用ANSI转义码局部更新
    长时间运行内存泄漏未释放旧对象引用及时覆盖变量避免累积
    容器环境偏差cgroups限制了CPU配额结合/sys/fs/cgroup/cpu校正

    五、系统集成与可视化增强方案

    将原始数据接入Prometheus或Grafana等监控平台,可通过Exporter暴露指标。例如,定义如下metrics端点:

    # HELP cpu_usage_percent CPU usage percentage per core
    # TYPE cpu_usage_percent gauge
    cpu_usage_percent{core="cpu0"} 23.4
    cpu_usage_percent{core="cpu1"} 18.7
    cpu_usage_percent{core="total"} 21.0
        

    此外,利用matplotlibplotext可在终端绘制实时趋势图,提升交互体验。

    六、流程建模:CPU监控数据流设计

    下图为从内核到用户界面的数据流动逻辑:

    graph TD
        A[/proc/stat] --> B{解析字段}
        B --> C[提取user,nice,system,idle等]
        C --> D[第一次采样存档]
        D --> E[延时等待]
        E --> F[第二次采样]
        F --> G[计算时间差]
        G --> H[得出使用率]
        H --> I[格式化输出]
        I --> J[刷新显示或上报]
        J --> K{继续循环?}
        K -- 是 --> E
        K -- 否 --> L[退出程序]
        

    七、常见陷阱与调试技巧

    开发者常遇到的问题包括:

    1. 误将cpu行与cpu0混淆,导致重复计算
    2. 忽略steal时间,在虚拟化环境中造成低估
    3. 未处理jiffies溢出(虽罕见但理论上存在)
    4. 在低负载机器上idle变化极小,易产生“100%”假象
    5. 跨容器/VM边界时缺乏上下文感知能力
    6. Python中未使用上下文管理器导致文件句柄泄露
    7. Shell脚本中未正确处理空格或字段偏移
    8. 未考虑NUMA架构下的CPU拓扑分布
    9. 日志轮转时干扰采样周期一致性
    10. 多线程环境下共享状态竞争
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 11月17日
  • 创建了问题 11月16日