《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门!
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界
系统管理员和开发者经常需要监控服务器或个人电脑的性能,以便及时发现瓶颈、优化资源利用率,甚至预测潜在问题。Python 的 psutil 库提供了一个强大、跨平台的方式来获取各种系统指标,如 CPU 使用率、内存占用、磁盘 I/O、网络流量等。本文将深入探讨 psutil 的功能,结合大量代码示例(包括详细的中文注释)和 LaTeX 数学公式,展示如何利用它构建全面的系统监控工具。您将学会如何收集、处理和展示性能数据,最终实现对系统健康状况的全面掌控。本文的目标是让您能够构建自己的定制化监控解决方案,或将 psutil 集成到现有的运维工具链中。
1. 引言:为什么我们需要系统监控?
在数字化时代,无论是个人电脑还是大型服务器集群,系统的稳定性和性能都至关重要。系统监控就像是给我们的数字基础设施安装了一个“健康检查仪”,可以帮助我们:
及时发现问题: 在系统崩溃或性能严重下降之前,预警潜在的硬件故障、资源耗尽等问题。
优化性能: 识别系统瓶颈,例如 CPU 过载、内存不足、磁盘 I/O 阻塞等,从而进行针对性的优化。
资源规划: 了解系统资源的使用趋势,预测未来的需求,为扩容或缩容提供依据。
故障排除: 当问题发生时,提供详细的性能数据,帮助快速定位问题的根源。
安全审计: 监控异常的网络流量、进程活动等,有助于发现潜在的安全威胁。
psutil (process and system utilities) 是一个跨平台的 Python 库,可以轻松获取系统和进程的各种信息,是实现系统监控的理想工具。
2. psutil 库:安装与初步探索
2.1 安装
安装 psutil 非常简单,使用 pip 即可:
pip install psutil
2.2 初步探索:获取 CPU 信息
让我们从获取 CPU 信息开始,体验 psutil 的便捷性:
# 导入 psutil 库
import psutil
# 获取 CPU 逻辑核心数
cpu_count_logical = psutil.cpu_count()
print(f"CPU 逻辑核心数: {
cpu_count_logical}")
# 获取 CPU 物理核心数
cpu_count_physical = psutil.cpu_count(logical=False)
print(f"CPU 物理核心数: {
cpu_count_physical}")
# 获取 CPU 使用率(每隔 1 秒刷新一次)
for i in range(5): # 监控5次
cpu_percent = psutil.cpu_percent(interval=1)
print(f"CPU 使用率: {
cpu_percent}%")
这段代码展示了如何获取 CPU 的逻辑核心数、物理核心数,以及每秒的 CPU 使用率。psutil.cpu_percent() 函数的 interval 参数指定了采样间隔。
3. CPU 监控:深入挖掘
3.1 CPU 详细使用率
除了总体 CPU 使用率,psutil 还可以提供更详细的信息:
# 获取 CPU 的详细使用率信息
cpu_times_percent = psutil.cpu_times_percent(interval=1)
print(f"用户态 CPU 使用率: {
cpu_times_percent.user}%")
print(f"内核态 CPU 使用率: {
cpu_times_percent.system}%")
print(f"空闲 CPU 使用率: {
cpu_times_percent.idle}%")
print(f"I/O 等待 CPU 使用率: {
cpu_times_percent.iowait}%") # 注意:某些系统可能不支持
# ... 其他指标,如 nice, irq, softirq, steal, guest, guest_nice
cpu_times_percent() 返回一个命名元组,包含了 CPU 在不同模式下花费时间的百分比。这些指标对于分析 CPU 负载的类型非常有用。例如,如果 iowait 很高,可能表示磁盘 I/O 存在瓶颈。
3.2 CPU 负载:平均负载
除了瞬时使用率,我们还可以获取系统的平均负载,这是一个反映系统繁忙程度的指标:
# 获取系统平均负载(1 分钟、5 分钟、15 分钟)
load_avg = psutil.getloadavg()
print(f"1 分钟平均负载: {
load_avg[0]}")
print(f"5 分钟平均负载: {
load_avg[1]}")
print(f"15 分钟平均负载: {
load_avg[2]}")
# 建议:将平均负载除以 CPU 核心数,得到一个更直观的指标
load_avg_per_core = [x / psutil.cpu_count() for x in load_avg]
print(f"每核心 1 分钟平均负载: {
load_avg_per_core[0]:.2f}")
print(f"每核心 5 分钟平均负载: {
load_avg_per_core[1]:.2f}")
print(f"每核心 15 分钟平均负载: {
load_avg_per_core[2]:.2f}")
平均负载表示在一段时间内,系统中处于可运行状态(正在使用 CPU 或等待 CPU)的平均进程数。一般来说,如果每核心的平均负载持续高于 0.7,就可能需要关注系统的性能问题。
3.3 CPU 频率
# 获取当前 CPU 频率
cpu_freq = psutil.cpu_freq()
print(f"当前 CPU 频率: {
cpu_freq.current} MHz")
print(f"最小 CPU 频率: {
cpu_freq.min} MHz")
print(f"最大 CPU 频率: {
cpu_freq.max} MHz")
cpu_freq() 返回一个命名元组,其中包含了当前频率、最小频率和最大频率。
3.4 CPU 温度 (部分硬件支持)
# 获取 CPU 温度(如果硬件支持)
try:
cpu_temperatures = psutil.sensors_temperatures()
if 'coretemp' in cpu_temperatures: #不同平台,key值可能不同
for entry in cpu_temperatures['coretemp']:
print(f"{
entry.label}: {
entry.current}°C")
except AttributeError:
print("无法获取 CPU 温度信息。")
部分硬件和操作系统可能不支持该功能。
4. 内存监控
4.1 内存使用情况
# 获取内存使用情况
memory = psutil.virtual_memory()
print(f"总内存: {
memory.total / (1024 ** 3):.2f} GB") # 转换为 GB
print(f"已使用内存: {
memory.used / (1024 ** 3):.2f} GB")
print(f"可用内存: {
memory.available / (1024 ** 3):.2f} GB")
print(f"内存使用率: {
memory.percent}%")
print(f"空闲内存: {
memory.free/ (1024 ** 3):.2f} GB")
# ... 其他指标,如 active, inactive, buffers, cached, shared, slab
psutil.virtual_memory() 返回一个命名元组,包含了各种内存指标。total 是总内存,used 是已使用的内存,available 是可供应用程序使用的内存(包括空闲内存和可回收的缓存),percent 是内存使用率。
4.2 Swap 交换分区
# 获取 Swap 交换分区使用情况
swap = psutil.swap_memory()
print(f"总 Swap 空间: {
swap.total / (1024 ** 3):.2f} GB")
print(f"已使用 Swap 空间: {
swap.used / (1024 ** 3):.2f} GB")
print(f"空闲 Swap 空间: {
swap.free / (1024 ** 3):.2f} GB")
print(f"Swap 使用率: {
swap.percent}%")
print(f"从磁盘换入内存: {
swap.sin / (1024 ** 3):.2f} GB") #数据量
print(f"从内存换出到磁盘: {
swap.sout / (1024 ** 3):.2f} GB")#数据量
Swap 交换分区是在物理内存不足时,将一部分硬盘空间用作内存的区域。swap_memory() 提供了 Swap 分区的总大小、已用大小、空闲大小、使用率等信息。sin 和 sout 分别表示从磁盘换入内存和从内存换出到磁盘的数据量。
5. 磁盘监控
5.1 磁盘分区信息
# 获取磁盘分区信息
partitions = psutil.disk_partitions()
for partition in partitions:
print(f"设备: {
partition.device}")
print(f"挂载点: {
partition.mountpoint}")
print(f"文件系统类型: {
partition.fstype}")
try:
usage = psutil.disk_usage(partition.mountpoint)
print(f" 总空间: {
usage.total / (1024 ** 3):.2f} GB")
print(f" 已用空间: {
usage.used / (1024 ** 3):.2f} GB")
print(f" 空闲空间: {
usage.free / (1024 ** 3):.2f} GB")
print(f" 使用率: {
usage.percent}%")
except PermissionError:
print(" 无权限访问该分区信息。")
这段代码会列出所有磁盘分区及其详细信息,包括设备名、挂载点、文件系统类型、总空间、已用空间、空闲空间和使用率。
5.2 磁盘 I/O 统计
# 获取磁盘 I/O 统计信息
disk_io = psutil.disk_io_counters()
print(f"读取次数: {
disk_io.read_count}")
print(f"写入次数: {
disk_io.write_count}")
print(f"读取字节数: {
disk_io.read_bytes / (1024 ** 3):.2f} GB")
print(f"写入字节数: {
disk_io.write_bytes / (1024 ** 3):.2f} GB")
print(f"读取时间: {
disk_io.read_time} ms")
print(f"写入时间: {
disk_io.write_time} ms")
# 可以针对每个磁盘单独获取 I/O 统计
for disk, io in psutil.disk_io_counters(perdisk=True).items():
print(f"磁盘 {
disk}:")
print(f" 读取次数: {
io.read_count}")
print(f" 写入次数: {
io.write_count}")
# ... 其他指标
psutil.disk_io_counters() 返回磁盘的 I/O 统计信息,包括读写次数、读写字节数、读写时间等。通过 perdisk=True 参数,可以获取每个磁盘的独立 I/O 统计。
6. 网络监控
6.1 网络接口信息
# 获取网络接口信息
net_io = psutil.net_io_counters(pernic=True)
for interface, io in net_io.items():
print(f"接口 {
interface}:")
print(f" 发送字节数: {
io.bytes_sent / (1024 ** 2):.2f} MB")
print(f" 接收字节数: {
io.bytes_recv / (1024 ** 2):.2f} MB")
print(f" 发送数据包数: {
io.packets_sent}")
print(f" 接收数据包数: {
io.packets_recv}")
print(f" 接收错误数: {
io.errin}")
print(f" 发送错误数: {
io.errout}")
print(f" 接收丢包数: {
io.dropin}")
print(f" 发送丢包数: {
io.dropout}")
# 获取网络连接信息
connections = psutil.net_connections()
for conn in connections:
print(conn)
这段代码展示了如何获取每个网络接口的 I/O 统计信息,包括发送和接收的字节数、数据包数、错误数、丢包数等。 还可以获取当前的上网络连接
6.2 网卡状态
import psutil
addrs = psutil.net_if_addrs()
for interface_name, interface_addresses in addrs.items():
print(f"接口: {
interface_name}")
for address in interface_addresses:
print(f" Address Family: {
address.family}")
print(f" Address: {
address.address}")
print(f" Netmask: {
address.netmask}")
print(f" Broadcast Address: {
address.broadcast}")
print(f" PTP Destination: {
address.ptp}")
这段代码可以枚举出网卡的详细状态。
7. 进程监控
7.1 获取进程列表
# 获取所有进程的 PID 列表
pids = psutil.pids()
for pid in pids:
try:
p = psutil.Process(pid)
print(f"PID: {
pid}, 进程名: {
p.name()}, 状态: {
p.status()}, 命令行: {
p.cmdline()}")
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass # 忽略可能出现的异常
psutil.pids() 返回所有进程的 PID 列表。psutil.Process() 可以根据 PID 获取进程对象,进而获取进程的各种信息,如进程名、状态、命令行参数等。
7.2 进程详细信息
# 获取指定 PID 的进程信息
pid_to_monitor = 1234 # 替换为你要监控的 PID
try:
p = psutil.Process(pid_to_monitor)
print(f"进程名: {
p.name()}")
print(f"命令行: {
p.cmdline()}")
print(f"状态: {
p.status()}")
print(f"父进程 PID: {
p.ppid()}")
print(f"CPU 使用率: {
p.cpu_percent()}%")
print(f"内存使用率: {
p.memory_percent()}%")
print(f"打开的文件数: {
p.num_fds()}") # Linux/macOS
print(f"线程数: {
p.num_threads()}")
print(f"创建时间: {
p.create_time()}") #unix时间戳
# 获取进程打开的文件列表
open_files = p.open_files()
for file in open_files:
print(f" 打开的文件: {
file.path}")
# 获取进程的网络连接
connections = p.connections()
for conn in connections:
print(f" 本地地址: {
conn.laddr}, 远程地址: {
conn.raddr}, 状态: {
conn.status}")
# 获取进程的内存映射信息
# memory_maps = p.memory_maps() # 可能会消耗大量资源
# for mm in memory_maps:
# print(f" 路径: {mm.path}, 大小: {mm.rss / (1024 ** 2):.2f} MB")
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
print(f"无法获取 PID 为 {
pid_to_monitor} 的进程信息。")
这段代码展示了如何获取一个指定 PID 进程的各种详细信息,包括进程名、命令行、状态、父进程 PID、CPU 使用率、内存使用率、打开的文件数、线程数、创建时间、打开的文件列表、网络连接等。
7.3 进程树
# 递归打印进程树
def print_process_tree(pid, indent=""):
try:
p = psutil.Process(pid)
print(f"{
indent}PID: {
pid}, 进程名: {
p.name()}")
for child in p.children():
print_process_tree(child.pid, indent + " ")
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
# 从根进程(PID 1)开始打印进程树
print_process_tree(1)
这段代码实现了一个递归函数 print_process_tree,用于打印进程树。它从指定的 PID 开始,递归地获取子进程并打印信息。
8. 其他系统信息
8.1 系统启动时间
# 获取系统启动时间
boot_time = psutil.boot_time()
print(f"系统启动时间: {
boot_time}") #unix时间戳
import datetime
print(f"系统启动时间: {
datetime.datetime.fromtimestamp(boot_time).strftime('%Y-%m-%d %H:%M:%S')}")
# 获取当前登录用户信息
users = psutil.users()
for user in users:
print(f"用户名: {
user.name}")
print(f"终端: {
user.terminal}")
print(f"登录时间: {
datetime.datetime.fromtimestamp(user.started).strftime('%Y-%m-%d %H:%M:%S')}")
print(f"主机: {
user.host}")
psutil.users() 返回一个列表,包含了当前登录用户的信息,如用户名、终端、登录时间、主机等。
8.3 传感器信息(温度、风扇、电池)
# 获取传感器信息(温度、风扇转速)
try:
temperatures = psutil.sensors_temperatures()
print("温度信息:")
for name, entries in temperatures.items():
print(f" {
name}:")
for entry in entries:
print(f" {
entry.label}: {
entry.current}°C")
fans = psutil.sensors_fans()
print("
风扇信息:")
for name, entries in fans.items():
print(f" {
name}:")
for entry in entries:
print(f" {
entry.label}: {
entry.current} RPM")
except AttributeError:
print("无法获取温度或风扇信息。")
# 获取电池信息(如果可用)
try:
battery = psutil.sensors_battery()
if battery:
print("
电池信息:")
print(f" 剩余电量: {
battery.percent}%")
print(f" 剩余时间: {
battery.secsleft / 3600:.2f} 小时") # 转换为小时
print(f" 电源状态: {
'已连接' if battery.power_plugged else '未连接'}")
except AttributeError:
print("无法获取电池信息。")
psutil.sensors_temperatures()、psutil.sensors_fans() 和 psutil.sensors_battery() 分别用于获取温度、风扇和电池信息。请注意,这些功能的支持程度取决于硬件和操作系统。
9. 构建实用的监控工具
有了 psutil 提供的丰富功能,我们可以构建各种实用的监控工具。下面是一些示例:
9.1 简单的命令行监控工具
import time
import os
def clear_screen():
os.system('cls' if os.name == 'nt' else 'clear')
def monitor():
while True:
clear_screen()
print("=" * 40)
print("系统监控 (按 Ctrl+C 退出)")
print("=" * 40)
# CPU 信息
print(f"CPU 使用率: {
psutil.cpu_percent()}%")
load_avg = [x / psutil.cpu_count() for x in psutil.getloadavg()]
print(f"平均负载 (1/5/15 分钟): {
load_avg[0]:.2f}, {
load_avg[1]:.2f}, {
load_avg[2]:.2f}")
# 内存信息
memory = psutil.virtual_memory()
print(f"内存使用率: {
memory.percent}%")
print(f"已用内存: {
memory.used / (1024 ** 3):.2f} GB / {
memory.total / (1024 ** 3):.2f} GB")
# 磁盘信息(仅显示根分区)
disk_usage = psutil.disk_usage('/')
print(f"磁盘使用率: {
disk_usage.percent}%")
print(f"已用磁盘空间: {
disk_usage.used / (1024 ** 3):.2f} GB / {
disk_usage.total / (1024 ** 3):.2f} GB")
# 网络信息(仅显示总流量)
net_io = psutil.net_io_counters()
print(f"网络发送: {
net_io.bytes_sent / (1024 ** 2):.2f} MB, 接收: {
net_io.bytes_recv / (1024 ** 2):.2f} MB")
time.sleep(2) # 每 2 秒刷新一次
if __name__ == "__main__":
try:
monitor()
except KeyboardInterrupt:
print("
监控已停止。")
这个简单的脚本会在命令行中实时显示 CPU 使用率、平均负载、内存使用情况、磁盘使用情况和网络流量。每 2 秒刷新一次,按 Ctrl+C 可以退出。
9.2 生成 HTML 报告
import jinja2 # 需要安装 jinja2:pip install jinja2
def generate_html_report():
# 收集数据
cpu_percent = psutil.cpu_percent()
load_avg = [x / psutil.cpu_count() for x in psutil.getloadavg()]
memory = psutil.virtual_memory()
disk_usage = psutil.disk_usage('/')
net_io = psutil.net_io_counters()
# 加载 Jinja2 模板
template_loader = jinja2.FileSystemLoader(searchpath="./")
template_env = jinja2.Environment(loader=template_loader)
template_file = "report_template.html" # 模板文件名
template = template_env.get_template(template_file)
# 渲染模板
output_text = template.render(
cpu_percent=cpu_percent,
load_avg=load_avg,
memory=memory,
disk_usage=disk_usage,
net_io=net_io,
datetime=datetime
)
# 将报告写入 HTML 文件
with open("system_report.html", "w") as f:
f.write(output_text)
print("已生成系统报告: system_report.html")
# 创建 report_template.html 文件,内容如下:
"""
<!DOCTYPE html>
<html>
<head>
<title>系统性能报告</title>
</head>
<body>
<h1>系统性能报告</h1>
<p>生成时间: {
{ datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') }}</p>
<h2>CPU</h2>
<p>CPU 使用率: {
{ cpu_percent }}%</p>
<p>平均负载 (1/5/15 分钟): {
{ load_avg[0]:.2f }}, {
{ load_avg[1]:.2f }}, {
{ load_avg[2]:.2f }}</p>
<h2>内存</h2>
<p>内存使用率: {
{ memory.percent }}%</p>
<p>已用内存: {
{ memory.used / (1024 ** 3):.2f }} GB / {
{ memory.total / (1024 ** 3):.2f }} GB</p>
<h2>磁盘 (/)</h2>
<p>磁盘使用率: {
{ disk_usage.percent }}%</p>
<p>已用磁盘空间: {
{ disk_usage.used / (1024 ** 3):.2f }} GB / {
{ disk_usage.total / (1024 ** 3):.2f }} GB</p>
<h2>网络</h2>
<p>网络发送: {
{ net_io.bytes_sent / (1024 ** 2):.2f }} MB, 接收: {
{ net_io.bytes_recv / (1024 ** 2):.2f }} MB</p>
</body>
</html>
"""
if __name__ == "__main__":
generate_html_report()
这个例子使用 Jinja2 模板引擎生成一个 HTML 格式的系统报告。你需要先创建一个名为 report_template.html 的模板文件,然后在 Python 脚本中收集数据、加载模板、渲染模板,最后将结果写入 HTML 文件。
9.3 使用 Matplotlib 绘制图表 (进阶)
import matplotlib.pyplot as plt
# 如果没有安装matplotlib, 需要安装: pip install matplotlib
def plot_cpu_usage(history):
plt.figure(figsize=(10, 6))
plt.plot(history)
plt.xlabel("Time (seconds)")
plt.ylabel("CPU Usage (%)")
plt.title("CPU Usage Over Time")
plt.grid(True)
plt.ylim(0, 100) # 设置 y 轴范围
plt.show()
def plot_memory_usage(history):
plt.figure(figsize=(10,6))
plt.plot(history)
plt.xlabel("Time (seconds)")
plt.ylabel("Memory Usage (%)")
plt.title("Memory Usage Over Time")
plt.grid(True)
plt.ylim(0,100)
plt.show()
def monitor_and_plot():
cpu_history = []
memory_history = []
try:
while True:
cpu_history.append(psutil.cpu_percent())
memory_history.append(psutil.virtual_memory().percent)
time.sleep(1)
if len(cpu_history) > 60: #保留60个点(1分钟数据)
cpu_history.pop(0)
if len(memory_history) > 60:
memory_history.pop(0)
except KeyboardInterrupt:
print("
监控已停止,正在生成图表...")
plot_cpu_usage(cpu_history)
plot_memory_usage(memory_history)
if __name__ == "__main__":
monitor_and_plot()
这个示例使用 Matplotlib 库绘制 CPU 使用率和内存使用率的实时图表。它会持续监控 CPU 和内存,并将数据保存在历史列表中,然后在用户按下 Ctrl+C 时绘制图表。
10. 高级应用与进阶
10.1 与数据库集成
可以将 psutil 收集的数据存储到数据库中,例如 SQLite、MySQL、PostgreSQL 或时间序列数据库(如 InfluxDB、Prometheus),以便进行长期存储、分析和可视化。
import sqlite3
import time
def create_database():
conn = sqlite3.connect('system_metrics.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS cpu_metrics (
timestamp INTEGER,
cpu_percent REAL
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS memory_metrics (
timestamp INTEGER,
memory_percent REAL
)
''')
conn.commit()
conn.close()
def insert_data(cpu_percent, memory_percent):
conn = sqlite3.connect('system_metrics.db')
cursor = conn.cursor()
timestamp = int(time.time())
cursor.execute("INSERT INTO cpu_metrics (timestamp, cpu_percent) VALUES (?, ?)", (timestamp, cpu_percent))
cursor.execute("INSERT INTO memory_metrics (timestamp, memory_percent) VALUES(?,?)", (timestamp, memory_percent))
conn.commit()
conn.close()
def monitor_and_store():
create_database()
while True:
cpu_percent = psutil.cpu_percent()
memory_percent = psutil.virtual_memory().percent
insert_data(cpu_percent, memory_percent)
time.sleep(60) # 每分钟记录一次
if __name__ == "__main__":
try:
monitor_and_store()
except KeyboardInterrupt:
print("
监控已停止。")
这个例子展示了如何将 CPU 和内存使用率数据存储到 SQLite 数据库中。您可以根据需要修改代码以适应其他数据库。
10.2 与监控系统集成
可以将 psutil 集成到现有的监控系统中,例如 Zabbix、Nagios、Grafana 等。通常,这需要编写自定义脚本或插件,将 psutil 收集的数据发送到监控系统。
以Zabbix为例,可以创建一个自定义的Zabbix agent脚本:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# zabbix_psutil.py (需要放在Zabbix Agent的UserParameter配置目录中)
# 在 zabbix_agentd.conf 中配置:
# UserParameter=system.cpu.percent,python3 /path/to/zabbix_psutil.py cpu_percent
# UserParameter=system.memory.percent,python3 /path/to/zabbix_psutil.py memory_percent
import psutil
import sys
def get_cpu_percent():
return psutil.cpu_percent()
def get_memory_percent():
return psutil.virtual_memory().percent
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python zabbix_psutil.py <metric_name>")
sys.exit(1)
metric_name = sys.argv[1]
if metric_name == "cpu_percent":
print(get_cpu_percent())
elif metric_name == "memory_percent":
print(get_memory_percent())
else:
print("Invalid metric name.")
sys.exit(1)
10.3 告警和通知
可以基于 psutil 收集的数据设置告警规则,并在触发告警时发送通知。例如,当 CPU 使用率超过 90% 时,发送电子邮件或短信通知。
import smtplib
from email.mime.text import MIMEText
def send_email(subject, body, sender, recipients, password):
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = ', '.join(recipients)
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp_server: #以gmail为例,需要设置允许不太安全的应用访问
smtp_server.login(sender, password)
smtp_server.sendmail(sender, recipients, msg.as_string())
print("邮件发送成功!")
def monitor_and_alert():
cpu_threshold = 90
memory_threshold = 90
sender_email = "your_email@gmail.com" # 发件人邮箱
sender_password = "your_password" # 发件人邮箱密码/授权码
recipient_emails = ["recipient1@example.com", "recipient2@example.com"] # 收件人邮箱列表
while True:
cpu_percent = psutil.cpu_percent()
memory_percent = psutil.virtual_memory().percent
if cpu_percent > cpu_threshold:
subject = "CPU 使用率过高警告!"
body = f"当前 CPU 使用率: {
cpu_percent}%"
send_email(subject, body, sender_email, recipient_emails, sender_password)
if memory_percent > memory_threshold:
subject = "内存使用率过高警告!"
body = f"当前内存使用率: {
memory_percent}%"
send_email(subject, body, sender_email, recipient_emails, sender_password)
time.sleep(60)
if __name__ == "__main__":
try:
monitor_and_alert()
except KeyboardInterrupt:
print("监控停止")
except Exception as e:
print(f"发生错误:{
e}")
这个示例演示了如何在 CPU 或内存使用率超过阈值时发送电子邮件通知。您可以使用类似的方法发送短信、Slack 消息等。
11. 性能优化与注意事项
采样间隔: psutil 的一些函数(如 cpu_percent())需要指定采样间隔。过短的间隔会增加 CPU 开销,过长的间隔则可能错过短暂的峰值。需要根据实际需求进行权衡。
资源消耗: 频繁地获取大量系统信息可能会对系统性能产生一定影响。在生产环境中,应谨慎使用 psutil,避免过度监控。
异常处理: 在访问进程信息时,可能会遇到 NoSuchProcess、AccessDenied、ZombieProcess 等异常。务必进行适当的异常处理。
跨平台兼容性: 虽然 psutil 是跨平台的,但某些功能的可用性可能因操作系统而异。在编写代码时,要注意处理可能出现的差异。
权限问题: 部分操作可能需要管理员权限。
12. 总结
psutil 是一个功能强大的 Python 库,为系统监控提供了丰富而便捷的接口。通过本文的学习,您应该已经掌握了如何使用 psutil 获取 CPU、内存、磁盘、网络和进程等各种系统信息,并能够构建简单的监控工具、生成报告、与数据库集成、设置告警等。
psutil 的应用远不止于此。您可以将其与其他工具和技术结合,构建更复杂的监控系统、自动化运维工具、性能分析工具等。掌握 psutil,将为您的系统管理和开发工作带来极大的便利。
数学公式示例 (LaTeX)
虽然本文主要关注 psutil 的使用,但为了完整性,这里提供一些可能与系统监控相关的数学公式示例:
指数加权移动平均 (Exponentially Weighted Moving Average, EWMA):
EWMA 是一种常用的平滑数据的方法,可以用于处理 CPU 使用率、内存使用率等时间序列数据,以减少噪声并突出趋势。
S t = { Y t , t = 0 α Y t + ( 1 − α ) S t − 1 , t > 0 S_t = egin{cases} Y_t, & t = 0 \ alpha Y_t + (1 – alpha)S_{t-1}, & t > 0 end{cases} St={
Yt,αYt+(1−α)St−1,t=0t>0其中:
S _ t S\_t S_t 是在时间 t 的 EWMA 值。
Y _ t Y\_t Y_t 是在时间 t 的实际观测值。
a l p h a \alpha alpha 是平滑因子,取值范围为 (0, 1)。 a l p h a \alpha alpha 越大,最近的观测值权重越大,对变化的响应越快; a l p h a \alpha alpha 越小,越多的历史数据被考虑,曲线越平滑。
在 Python 中,可以使用 pandas 库来计算 EWMA:
import pandas as pd
import numpy as np
import psutil
import time
# 如果没有安装pandas, 需要安装: pip install pandas
def get_cpu_usage_series(interval=1, num_points=60):
"""获取 CPU 使用率时间序列"""
cpu_usage = []
for _ in range(num_points):
cpu_usage.append(psutil.cpu_percent(interval=interval))
return pd.Series(cpu_usage)
def calculate_ewma(series, alpha=0.1):
"""计算指数加权移动平均"""
return series.ewm(alpha=alpha).mean()
if __name__ == "__main__":
cpu_series = get_cpu_usage_series()
ewma_series = calculate_ewma(cpu_series)
print("原始 CPU 使用率:", cpu_series.values)
print("EWMA 后的 CPU 使用率:", ewma_series.values)
# 可以结合 Matplotlib 绘图
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
plt.plot(cpu_series, label="Original")
plt.plot(ewma_series, label="EWMA (alpha=0.1)")
plt.xlabel("Time")
plt.ylabel("CPU Usage (%)")
plt.legend()
plt.title("CPU Usage with EWMA")
plt.show()
标准差 (Standard Deviation):
标准差用于衡量数据的离散程度。在系统监控中,可以用来衡量 CPU 使用率、内存使用率等指标的波动性。
σ = 1 N ∑ i = 1 N ( x i − μ ) 2 sigma = sqrt{frac{1}{N}sum_{i=1}^{N}(x_i – mu)^2} σ=N1i=1∑N(xi−μ)2
其中:
s i g m a \sigma sigma 是标准差。
N N N 是数据点的数量。
x _ i x\_i x_i 是第 i 个数据点的值。
m u \mu mu 是数据的平均值。
在 Python 中,可以使用 numpy 来计算标准差:
```python
import numpy as np
cpu_usage = [10, 12, 15, 13, 18, 20, 17, 15, 14, 16] # 示例数据
std_dev = np.std(cpu_usage)
print(f"CPU使用率的标准差: {std_dev:.2f}")
```
百分位数 (Percentiles)
百分位数用于表示数据集中特定百分比的数据点所在的位置。在监控领域,常用的有 P95, P99(95%, 99%)等。
计算方法:将数据从小到大排序,P95 表示有 95% 的数据点小于或等于该值。
import numpy as np
cpu_usage = [10, 12, 15, 13, 18, 20, 17, 15, 14, 16, 80, 95] # 示例数据(有异常值)
p95 = np.percentile(cpu_usage, 95)
print(f"CPU 使用率的 P95: {
p95}")
相关系数 (Correlation Coefficient)
相关系数用来衡量两个变量之间的线性相关程度。例如,可以用它来分析 CPU 使用率和内存使用率之间的关系。
皮尔逊相关系数 (Pearson Correlation Coefficient) 公式:
r = frac{sum_{i=1}^{n}(X_i – ar{X})(Y_i – ar{Y})}{sqrt{sum_{i=1}^{n}(X_i – ar{X})2}sqrt{sum_{i=1}{n}(Y_i – ar{Y})^2}}
其中:
r r r 是皮尔逊相关系数。
X _ i X\_i X_i 和 Y _ i Y\_i Y_i 是两个变量的第 i 个观测值。
b a r X \bar{X} barX 和 b a r Y \bar{Y} barY 分别是两个变量的平均值。
在 Python 中,可以使用 numpy 或 scipy 来计算相关系数:
import numpy as np
from scipy.stats import pearsonr
# 示例数据
cpu_usage = [10, 12, 15, 13, 18, 20, 17, 15, 14, 16]
memory_usage = [30, 32, 35, 33, 38, 40, 37, 35, 34, 36]
# 使用 numpy 计算
correlation_np = np.corrcoef(cpu_usage, memory_usage)[0, 1]
print(f"使用 NumPy 计算的相关系数: {
correlation_np:.2f}")
# 使用 scipy 计算
correlation_scipy, _ = pearsonr(cpu_usage, memory_usage)
print(f"使用 SciPy 计算的相关系数: {
correlation_scipy:.2f}")
13. 补充案例:结合 Flask 构建 Web 监控仪表盘
为了更直观地展示监控数据,我们可以使用 Flask(一个轻量级的 Web 框架)和 Chart.js(一个 JavaScript 图表库)构建一个简单的 Web 监控仪表盘。
项目结构:
system_monitor/
├── app.py (Flask 应用)
├── templates/
│ └── index.html (HTML 模板)
└── static/
├── css/
│ └── style.css (样式)
└── js/
└── chart.min.js (Chart.js 库,从 https://www.chartjs.org/ 下载)
└── app.js (前端逻辑)
app.py (Flask 应用):
from flask import Flask, render_template, jsonify
import psutil
import time
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/data")
def get_data():
cpu_percent = psutil.cpu_percent()
memory_percent = psutil.virtual_memory().percent
return jsonify(cpu_percent=cpu_percent, memory_percent=memory_percent)
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0') # 允许外部访问
templates/index.html (HTML 模板):
<!DOCTYPE html>
<html>
<head>
<title>系统监控仪表盘</title>
<link rel="stylesheet" href="{
{ url_for('static', filename='css/style.css') }}">
<script src="{
{ url_for('static', filename='js/chart.min.js') }}"></script>
</head>
<body>
<h1>系统监控仪表盘</h1>
<div class="chart-container">
<canvas id="cpuChart"></canvas>
</div>
<div class="chart-container">
<canvas id="memoryChart"></canvas>
</div>
<script src="{
{ url_for('static', filename='js/app.js') }}"></script>
</body>
</html>
static/css/style.css (样式):
body {
font-family: sans-serif;
margin: 20px;
}
.chart-container {
width: 80%;
margin: 20px auto;
}
static/js/app.js (前端逻辑):
// CPU 图表
const cpuChartCtx = document.getElementById('cpuChart').getContext('2d');
const cpuChart = new Chart(cpuChartCtx, {
type: 'line',
data: {
labels: [], // 时间标签
datasets: [{
label: 'CPU 使用率 (%)',
data: [], // CPU 使用率数据
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 2,
fill: false
}]
},
options: {
scales: {
y: {
beginAtZero: true,
max: 100
}
}
}
});
// 内存图表
const memoryChartCtx = document.getElementById('memoryChart').getContext('2d');
const memoryChart = new Chart(memoryChartCtx, {
type: 'line',
data: {
labels: [], // 时间标签
datasets: [{
label: '内存使用率 (%)',
data: [], // 内存使用率数据
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 2,
fill: false
}]
},
options: {
scales: {
y: {
beginAtZero: true,
max: 100
}
}
}
});
// 更新图表数据的函数
function updateCharts() {
fetch('/data')
.then(response => response.json())
.then(data => {
const now = new Date().toLocaleTimeString(); // 获取当前时间
// 更新 CPU 图表
cpuChart.data.labels.push(now);
cpuChart.data.datasets[0].data.push(data.cpu_percent);
// 更新内存图表
memoryChart.data.labels.push(now);
memoryChart.data.datasets[0].data.push(data.memory_percent);
// 限制数据点数量 (例如,最多显示 60 个点)
const maxDataPoints = 60;
if (cpuChart.data.labels.length > maxDataPoints) {
cpuChart.data.labels.shift();
cpuChart.data.datasets[0].data.shift();
}
if(memoryChart.data.labels.length > maxDataPoints){
memoryChart.data.labels.shift();
memoryChart.data.datasets[0].data.shift();
}
cpuChart.update(); // 更新图表
memoryChart.update();
});
}
// 每秒更新一次数据
setInterval(updateCharts, 1000);
运行步骤:
确保安装了 Flask 和 psutil: pip install flask psutil
下载 Chart.js: 从 https://www.chartjs.org/ 下载 chart.min.js,并将其放入 static/js/ 目录。
创建上述文件和目录结构。
运行 app.py: python app.py
在浏览器中访问: http://localhost:5000 (或你的服务器地址)
这个 Web 仪表盘会实时显示 CPU 使用率和内存使用率的折线图。
这只是一个非常基础的示例,你可以根据自己的需求进行扩展,例如:
添加更多图表(磁盘 I/O、网络流量等)。
使用更高级的图表库(如 D3.js、Plotly)。
添加交互功能(如选择时间范围、缩放)。
添加用户认证。
部署到服务器上。





![效率神器:文件夹/程序/网址/注册表路径快速打开/跳转 QuickJump 3.0[2022.11.24] - 宋马](https://pic.songma.com/blogimg/20250421/d1bb99d3809a410d915a1b0de7b4a8ae.jpg)














暂无评论内容