当前位置: 首页 > news >正文

Python-适用于硬件测试的小工具

文末附源码

一、监控器核心功能亮点

这个系统资源监控器没有复杂的依赖,核心功能聚焦“实用”和“轻量”,主要亮点如下:

  • 多资源覆盖:支持CPU使用率、内存使用率监控,若有NVIDIA显卡,还能自动识别并监控GPU使用率。
  • 日志持久化:所有监控数据以CSV格式保存,包含时间戳,方便后续分析(比如用Excel或Python画趋势图)。
  • 实时可视化:UI界面实时预览最新数据,自动保留最近15条记录,避免信息过载。
  • 友好交互:支持自定义日志保存路径,按钮状态动态切换(开始后禁用“开始”按钮,防止重复点击),操作逻辑清晰。
  • 跨平台兼容:适配Windows和Linux系统的中文字体,避免UI乱码问题。

二、核心代码解析:关键模块如何实现?

整个项目代码约300行,核心分为UI构建资源监控数据记录三大模块,下面逐一拆解关键技术点。

1. 基础环境与依赖准备

首先要明确依赖库,项目用到3个核心库,功能各有分工:

  • tkinter:Python自带的GUI库,用于搭建界面(无需额外安装)。
  • psutil:跨平台系统监控库,获取CPU、内存等硬件信息(需安装:pip install psutil)。
  • pynvml:NVIDIA显卡监控库,仅用于NVIDIA GPU信息获取(需安装:pip install nvidia-ml-py3,AMD显卡暂不支持)。

代码开头的“依赖检测”逻辑很重要,能避免因缺少库导致程序崩溃:

# 尝试导入GPU监控库
try:import pynvml  # NVIDIA GPU监控has_nvml = True
except ImportError:has_nvml = False

2. UI构建:兼顾美观与实用性

UI部分用Tkinter实现,核心是“分区域布局”,让界面清晰不杂乱。主要分为5个区域:

  • 标题区:显示“系统资源监控器”,用加粗字体突出。
  • GPU信息区:自动检测GPU状态(如“检测到GPU: NVIDIA GeForce RTX 3060”),无GPU时显示友好提示。
  • 路径选择区:支持浏览选择CSV日志保存路径,默认文件名含时间戳(如system_monitor_20240520_143000.csv)。
  • 控制按钮区:“开始记录”(绿色)和“停止记录”(红色),状态动态切换。
  • 数据预览区:用Text组件显示实时数据,带滚动条,仅保留最近15行。

其中“中文字体适配”是容易踩坑的点,代码专门做了跨平台处理:

def setup_fonts(self):"""设置中文字体支持,避免乱码"""if sys.platform.startswith('win'):default_font = ('Microsoft YaHei UI', 9)title_font = ('Microsoft YaHei UI', 10, 'bold')else:default_font = ('SimHei', 9)title_font = ('SimHei', 10, 'bold')self.root.option_add("*Font", default_font)self.title_font = title_font

3. 资源监控:如何获取CPU/内存/GPU数据?

资源数据的获取是监控器的核心,代码用简洁的逻辑实现了多硬件支持:

(1)CPU与内存数据:基于psutil

psutil库封装了底层系统调用,几行代码就能获取关键数据:

  • CPU使用率:psutil.cpu_percent(interval=0.1)interval是采样间隔(0.1秒兼顾实时性和性能)。
  • 内存使用率:psutil.virtual_memory().percent,直接返回内存占用百分比。
(2)GPU数据:基于pynvml

NVIDIA GPU监控需要先初始化库,再获取设备句柄,最后读取使用率:

def init_gpu_monitoring(self):if has_nvml:try:pynvml.nvmlInit()  # 初始化库device_count = pynvml.nvmlDeviceGetCount()  # 检测GPU数量if device_count > 0:self.gpu_handle = pynvml.nvmlDeviceGetHandleByIndex(0)  # 获取第1块GPU句柄self.gpu_available = Truegpu_name = pynvml.nvmlDeviceGetName(self.gpu_handle).decode('utf-8')  # 转中文self.gpu_info = f"检测到GPU: {gpu_name}"except Exception as e:self.gpu_info = f"GPU初始化失败: {str(e)}"

获取GPU使用率时,用pynvml.nvmlDeviceGetUtilizationRates(),返回的gpu字段就是使用率百分比。

4. 数据记录:线程安全与日志持久化

如果直接在主线程循环记录数据,会导致UI卡顿(Tkinter是单线程GUI库)。因此代码用子线程处理数据记录,同时保证线程安全:

(1)线程创建与管理
  • 开始记录时,创建daemon子线程(daemon=True,主线程退出时子线程自动关闭)。
  • 停止记录时,通过self.is_recording = False控制循环退出,避免线程残留。
(2)CSV日志写入
  • 首次创建日志文件时,自动写入表头(“时间”“CPU使用率(%)”“内存使用率(%)”“GPU使用率(%)”)。
  • 后续记录以“追加模式”写入,避免覆盖历史数据,编码用utf-8防止中文乱码。

关键代码片段:

def record_data(self):while self.is_recording:# 1. 获取各类资源数据(CPU、内存、GPU)current_time = time.strftime("%Y-%m-%d %H:%M:%S")cpu_usage = psutil.cpu_percent(interval=0.1)mem_usage = psutil.virtual_memory().percentgpu_usage = self.get_gpu_usage()  # 自定义GPU获取函数# 2. 写入CSVwith open(self.log_path.get(), 'a', newline='', encoding='utf-8') as f:writer = csv.writer(f)row_data = [current_time, cpu_usage, mem_usage]if self.gpu_available:row_data.append(gpu_usage)writer.writerow(row_data)# 3. 更新UI预览(需用root.after确保主线程更新)self.update_preview(current_time, cpu_usage, mem_usage, gpu_usage)time.sleep(0.9)  # 控制记录间隔约1秒(加前面的0.1秒采样,共1秒)

5. 实时预览:控制数据显示规模

数据预览区用Text组件实现,但如果记录太久,文本会无限变长。代码加入了“行数控制”,仅保留最近15行:

def update_preview(self, time_str, cpu, mem, gpu):def update():self.data_text.config(state=tk.NORMAL)# 超过15行时,删除第一行line_count = int(self.data_text.index('end-1c').split('.')[0])if line_count > 15:self.data_text.delete('1.0', '2.0')# 追加新数据line = f"{time_str} - CPU: {cpu}%  内存: {mem}%"if self.gpu_available:line += f"  GPU: {gpu}%"self.data_text.insert(tk.END, line + "\n")self.data_text.see(tk.END)  # 自动滚动到最后一行self.data_text.config(state=tk.DISABLED)self.root.after(0, update)  # 确保UI操作在主线程执行

三、实战使用:3步上手监控系统资源

看完代码解析,我们来实际运行监控器,步骤非常简单:

1. 安装依赖

打开命令行,执行以下命令安装所需库:

pip install psutil nvidia-ml-py3

(如果没有NVIDIA显卡,可跳过nvidia-ml-py3,程序会自动忽略GPU监控)

2. 运行程序

将完整代码保存为system_monitor.py,然后用Python运行:

python system_monitor.py

3. 开始监控与查看日志

  1. 点击“浏览…”选择日志保存路径(默认会生成带时间戳的CSV文件名)。
  2. 点击“开始记录”,状态会变为“正在记录…”,数据预览区实时显示CPU/内存/GPU数据。
  3. 监控完成后点击“停止记录”,程序会弹出提示“日志已保存至xxx”。
  4. 找到保存的CSV文件,用Excel或Notepad打开,就能看到所有时间点的资源数据,方便后续分析。

四、总结与扩展方向

这个轻量级监控器虽然简单,但覆盖了“监控-记录-分析”的完整流程,适合个人日常使用。如果想进一步优化,可以考虑这些方向:

  • 支持多GPU监控:当前只监控第1块GPU,可扩展为选择多块GPU。
  • 添加磁盘使用率监控:用psutil.disk_usage('/')获取磁盘占用,丰富监控维度。
  • 数据可视化:在UI中加入Matplotlib图表,实时显示资源变化趋势。
  • 定时任务:支持设置监控时长(如“监控1小时后自动停止”)。

如果你需要快速监控系统资源,又不想安装复杂的工具(如Task Manager、nvidia-smi),这个Python监控器会是不错的选择。赶紧试试吧!

资源监控器源码:
import tkinter as tk
from tkinter import filedialog, messagebox
import psutil
import time
import csv
import threading
import os
import sys# 尝试导入GPU监控库
try:import pynvml  # NVIDIA GPU监控has_nvml = True
except ImportError:has_nvml = Falseclass SystemMonitor:def __init__(self, root):self.root = rootself.root.title("系统资源监控器")self.root.geometry("600x400")self.root.resizable(True, True)# 设置中文字体支持self.setup_fonts()# 变量初始化self.log_path = tk.StringVar()self.is_recording = Falseself.recording_thread = Noneself.gpu_available = Falseself.gpu_handle = None# 初始化GPU监控self.init_gpu_monitoring()# 创建UI组件self.create_widgets()def setup_fonts(self):"""设置中文字体支持"""if sys.platform.startswith('win'):default_font = ('Microsoft YaHei UI', 9)title_font = ('Microsoft YaHei UI', 10, 'bold')else:default_font = ('SimHei', 9)title_font = ('SimHei', 10, 'bold')self.root.option_add("*Font", default_font)self.title_font = title_fontdef init_gpu_monitoring(self):"""初始化GPU监控"""if has_nvml:try:pynvml.nvmlInit()device_count = pynvml.nvmlDeviceGetCount()if device_count > 0:self.gpu_handle = pynvml.nvmlDeviceGetHandleByIndex(0)self.gpu_available = Truegpu_name = pynvml.nvmlDeviceGetName(self.gpu_handle)if isinstance(gpu_name, bytes):gpu_name = gpu_name.decode('utf-8')self.gpu_info = f"检测到GPU: {gpu_name}"else:self.gpu_info = "未检测到GPU设备"except Exception as e:self.gpu_info = f"GPU初始化失败: {str(e)}"else:self.gpu_info = "未安装NVIDIA GPU监控库(pynvml)"def create_widgets(self):"""创建界面组件"""# 标题标签title_label = tk.Label(self.root, text="系统资源监控器", font=self.title_font)title_label.pack(pady=10)# GPU信息标签gpu_label = tk.Label(self.root, text=self.gpu_info, fg="gray")gpu_label.pack(pady=5)# 路径选择区域path_frame = tk.Frame(self.root)path_frame.pack(pady=10, fill=tk.X, padx=20)tk.Label(path_frame, text="日志文件路径:").pack(side=tk.LEFT)tk.Entry(path_frame, textvariable=self.log_path, width=50).pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)tk.Button(path_frame, text="浏览...", command=self.browse_path).pack(side=tk.LEFT, padx=5)# 控制按钮区域btn_frame = tk.Frame(self.root)btn_frame.pack(pady=15)self.start_btn = tk.Button(btn_frame, text="开始记录", command=self.start_recording, width=15, bg="#4CAF50", fg="white")self.start_btn.pack(side=tk.LEFT, padx=10)self.stop_btn = tk.Button(btn_frame, text="停止记录", command=self.stop_recording, width=15, bg="#f44336", fg="white", state=tk.DISABLED)self.stop_btn.pack(side=tk.LEFT, padx=10)# 状态区域status_frame = tk.Frame(self.root)status_frame.pack(pady=5, fill=tk.X, padx=20)tk.Label(status_frame, text="状态:").pack(side=tk.LEFT)self.status_var = tk.StringVar(value="就绪")tk.Label(status_frame, textvariable=self.status_var, fg="blue").pack(side=tk.LEFT, padx=5)# 数据显示区域tk.Label(self.root, text="监控数据预览:").pack(anchor=tk.W, padx=20, pady=(10, 5))self.data_text = tk.Text(self.root, height=10, wrap=tk.WORD)self.data_text.pack(pady=5, padx=20, fill=tk.BOTH, expand=True)self.data_text.config(state=tk.DISABLED)# 添加滚动条scrollbar = tk.Scrollbar(self.data_text)scrollbar.pack(side=tk.RIGHT, fill=tk.Y)self.data_text.config(yscrollcommand=scrollbar.set)scrollbar.config(command=self.data_text.yview)def browse_path(self):"""浏览并选择日志文件保存路径"""default_filename = f"system_monitor_{time.strftime('%Y%m%d_%H%M%S')}.csv"filename = filedialog.asksaveasfilename(defaultextension=".csv",filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")],title="选择日志文件保存位置",initialfile=default_filename)if filename:self.log_path.set(filename)def start_recording(self):"""开始记录系统资源使用情况"""if not self.log_path.get():messagebox.showwarning("警告", "请先选择日志文件保存路径")returnself.is_recording = Trueself.start_btn.config(state=tk.DISABLED)self.stop_btn.config(state=tk.NORMAL)self.status_var.set("正在记录...")# 检查文件是否存在,如果不存在则创建并写入表头if not os.path.exists(self.log_path.get()):try:with open(self.log_path.get(), 'w', newline='', encoding='utf-8') as f:writer = csv.writer(f)headers = ["时间", "CPU使用率(%)", "内存使用率(%)"]if self.gpu_available:headers.append("GPU使用率(%)")writer.writerow(headers)except Exception as e:messagebox.showerror("错误", f"无法创建日志文件: {str(e)}")self.reset_buttons()return# 启动记录线程self.recording_thread = threading.Thread(target=self.record_data)self.recording_thread.daemon = Trueself.recording_thread.start()def stop_recording(self):"""停止记录系统资源使用情况"""self.is_recording = Falseself.reset_buttons()self.status_var.set("已停止")messagebox.showinfo("信息", f"日志已保存至: {self.log_path.get()}")def reset_buttons(self):"""重置按钮状态"""self.start_btn.config(state=tk.NORMAL)self.stop_btn.config(state=tk.DISABLED)def record_data(self):"""记录系统资源数据的线程函数"""while self.is_recording:try:# 获取当前时间(精确到秒)current_time = time.strftime("%Y-%m-%d %H:%M:%S")# 获取CPU使用率cpu_usage = psutil.cpu_percent(interval=0.1)# 获取内存使用率mem = psutil.virtual_memory()mem_usage = mem.percent# 获取GPU使用率(如果可用)gpu_usage = Noneif self.gpu_available and has_nvml:try:gpu_util = pynvml.nvmlDeviceGetUtilizationRates(self.gpu_handle)gpu_usage = gpu_util.gpuexcept:gpu_usage = "N/A"# 写入日志文件with open(self.log_path.get(), 'a', newline='', encoding='utf-8') as f:writer = csv.writer(f)row_data = [current_time, cpu_usage, mem_usage]if self.gpu_available and gpu_usage is not None:row_data.append(gpu_usage)writer.writerow(row_data)# 在UI上显示最新数据self.update_preview(current_time, cpu_usage, mem_usage, gpu_usage)except Exception as e:error_msg = f"记录数据时出错: {str(e)}"self.status_var.set(error_msg)self.is_recording = Falseself.root.after(0, self.reset_buttons)self.root.after(0, lambda: messagebox.showerror("错误", error_msg))break# 等待1秒(减去前面操作已用的时间)time.sleep(0.9)def update_preview(self, time_str, cpu, mem, gpu):"""更新预览区域显示最新数据"""# 在UI线程中更新文本框def update():self.data_text.config(state=tk.NORMAL)# 保持只显示最后15行数据line_count = int(self.data_text.index('end-1c').split('.')[0])if line_count > 15:self.data_text.delete('1.0', '2.0')# 构建显示行line = f"{time_str} - CPU: {cpu}%  内存: {mem}%"if self.gpu_available and gpu is not None:line += f"  GPU: {gpu}%"self.data_text.insert(tk.END, line + "\n")self.data_text.see(tk.END)  # 滚动到最后一行self.data_text.config(state=tk.DISABLED)# 确保在主线程中更新UIself.root.after(0, update)if __name__ == "__main__":try:root = tk.Tk()# 设置窗口图标(可选)try:root.iconbitmap(default="")except:passapp = SystemMonitor(root)root.mainloop()except Exception as e:messagebox.showerror("程序错误", f"程序运行出错: {str(e)}")
http://www.dtcms.com/a/478510.html

相关文章:

  • 第三方软件测评机构:【Locust的性能测试和负载测试】
  • 【Python】列表 元组 字典 文件
  • 简单asp网站深圳做个商城网站设计
  • OpenTelemetry 入门
  • 昆山做网站找哪家好wordpress 算数验证码
  • 网站建设服务费入阿里云域名注册平台
  • 美颜的灵魂:磨皮技术的演进与实现原理详解
  • 自定义半精度浮点数modelsim仿真显示
  • 广东GEO优化哪家专业哪家服务好
  • 【C#】await Task.Delay(100)与Thread.Sleep(100)?
  • 从智能补全到云原生适配:免费IDE DataGrip的技术实践与行业趋势
  • 多摄像头网络压力测试
  • 信息发布网站设计巴中网站建设有限公司
  • 图像处理-opencv(一)
  • 空包网站分站怎么做重庆市工程建筑造价信息网
  • 基于MATLAB的Excel文件批量读取与循环处理
  • 网站建设方案拓扑图平面设计现在怎么样
  • 高并发下的优雅延迟:Python异步爬虫(aiohttp)的速率限制实践
  • Python爬虫实战:获取同花顺股票资金流向数据并做分析
  • MyBatis的SpringBootVFS解析
  • 上海网站建设好处自建网站教程
  • 网站建设的作用是什么网站建设沟通准备
  • 【中间件Linux在环境安装】SpringBoot应用环境安装(一)-JDK安装
  • 【Linux环境下安装】SpringBoot应用环境安装(二)-Redis安装
  • 如何设置 Visual Studio 在调试停止时自动关闭控制台
  • 网站建设佰首选金手指三十wordpress 切换中文字体
  • 网站搭建服务器需要多少钱厦门网站建设u
  • MPLS技术详解2:LDP标签分发协议原理与操作流程
  • 网站跟别的做的一样的网站群怎么做
  • java注解+AOP切面:实现sql片段动态插入