如何用Python获取与任务管理器一致的CPU使用率?
问题原因及解决方案
你的代码存在两个关键问题,导致psutil获取的CPU使用率和任务管理器数据不符:
1. 阻塞式调用打乱统计逻辑与Qt事件循环
你在update_value中每次调用psutil.cpu_percent(interval=1),这会阻塞当前线程1秒来计算这段时间的CPU使用率。而Qt定时器设置为每1秒触发一次更新,这就导致:
- 每次更新操作实际占用1秒阻塞时间,定时器下一次触发被延迟,实际更新间隔变成2秒左右
- 阻塞期间Qt界面无法响应其他事件,不仅会卡顿,还会导致CPU使用率的统计窗口和任务管理器的统计周期不匹配
2. 重复初始化基线的逻辑冗余
你在第一次调用时执行psutil.cpu_percent(interval=1)建立基线,紧接着又调用一次同样带interval=1的方法,两次调用间隔几乎为0,第二次统计的是第一次结束后1秒的使用率,完全浪费了一次阻塞时间。
修复后的代码
解决思路是使用非阻塞式的CPU使用率获取方式:第一次调用初始化基线,之后每次调用直接获取从上一次到当前的使用率,避免阻塞Qt主线程。
import sys import psutil # 获取CPU和内存使用率 from PyQt5 import QtWidgets, QtCore, QtGui class CircularProgressBar(QtWidgets.QWidget): def __init__(self, label="CPU", color=QtGui.QColor(255, 140, 0), parent=None): super().__init__(parent) self.label = label self.color = color self.value = 0 # 初始化CPU使用率基线,非阻塞 psutil.cpu_percent(interval=0) self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.update_value) self.timer.start(1000) # 每1秒更新一次 def update_value(self): # 非阻塞获取从上一次调用到现在的CPU使用率 self.value = psutil.cpu_percent(interval=0) self.update() def paintEvent(self, event): width = self.width() height = self.height() side = min(width, height) painter = QtGui.QPainter(self) painter.setRenderHint(QtGui.QPainter.Antialiasing) # 绘制背景圆 rect = QtCore.QRectF(10, 10, side - 20, side - 20) pen = QtGui.QPen(QtCore.Qt.gray, 10) painter.setPen(pen) painter.drawArc(rect, 0, 360 * 16) # 绘制进度弧 pen.setColor(self.color) painter.setPen(pen) angle = int(self.value * 360 / 100) * 16 painter.drawArc(rect, 90 * 16, -angle) # 绘制标签和百分比 painter.setPen(QtCore.Qt.white) painter.setFont(QtGui.QFont("Arial", side // 10)) painter.drawText(rect, QtCore.Qt.AlignCenter, f"{self.label}\n{self.value:.0f}%") painter.end() def main(): app = QtWidgets.QApplication(sys.argv) window = QtWidgets.QMainWindow() window.setWindowTitle("资源监视器") central_widget = QtWidgets.QWidget() layout = QtWidgets.QHBoxLayout(central_widget) cpu_bar = CircularProgressBar("CPU", QtGui.QColor(255, 140, 0)) cpu_bar.setMinimumSize(200, 200) layout.addWidget(cpu_bar) window.setCentralWidget(central_widget) window.resize(600, 400) window.show() sys.exit(app.exec_()) if __name__ == "__main__": main()
额外说明
psutil.cpu_percent(interval=0):立即返回从上一次调用该方法到当前的平均CPU使用率,不会阻塞线程- 初始化时调用一次
psutil.cpu_percent(interval=0)是为了建立统计基线,避免第一次获取到0值 - 修复后不仅CPU使用率的数值会和任务管理器一致,界面也不会再出现卡顿现象
内容的提问来源于stack exchange,提问作者Joan Venge
相关产品推荐
相关产品推荐

