psutil.net_io_counters() 返回的是累计值而非实时速率,需两次采样求差并除以时间间隔(建议≥0.5秒,用time.monotonic()计时);多网卡需按白名单过滤物理接口,避免虚拟接口干扰;windows下可能因权限或性能计数器未启用导致异常,应加异常处理和权限检查。

psutil.net_io_counters() 返回的数值是累计值,不是实时速率
很多人一上来就用 psutil.net_io_counters() 每秒调一次,直接把 bytes_sent 当成“当前发送速度”,结果画出来的图是一条直线上升的线。它返回的是自系统启动以来的总字节数,不是每秒增量。
要算实时速率,必须自己做两次采样、相减、再除以时间间隔:
- 至少间隔 0.5 秒以上采样,太短会导致浮点精度误差或归零(尤其低流量时)
- 第一次采样后 sleep 1 秒,第二次再调用,用差值除以 1.0 才是近似 B/s
- 别用
time.time()做间隔基准——用time.monotonic()更稳,避免系统时间回拨干扰
import psutil, time io1 = psutil.net_io_counters() time.sleep(1) io2 = psutil.net_io_counters() speed_bps = (io2.bytes_sent - io1.bytes_sent) / 1.0
不同网卡接口的数据不能混着加总
一台服务器可能有 eth0、docker0、vethxxxx、lo 多个接口,psutil.net_io_counters(pernic=True) 返回的是 dict,key 是接口名。直接对所有值求和会把 loopback 流量也算进去,导致监控值虚高 20%–50%(尤其容器密集环境)。
真实业务流量通常只走物理网卡或指定 bond 接口:
- 先用
psutil.net_if_addrs()过滤出有 IPv4 地址且非lo的接口名 - 排除
veth*、br-、docker0等虚拟接口(除非你明确要监控容器网络) - 生产环境建议配置白名单,比如只监控
['ens192', 'bond0'],而不是动态枚举
Windows 下 net_io_counters() 可能返回空或 KeyError
Windows 上某些精简版系统、Hyper-V 虚拟机、或启用了“网络连接状态指示器”优化时,psutil.net_io_counters() 可能抛 KeyError: 'bytes_sent',或者返回的 dict 缺少关键字段。这不是 bug,是 Windows 性能计数器没启用或权限不足。
稳妥做法是加 fallback 和日志:
- 捕获
KeyError和RuntimeError,记录警告并跳过本次采集 - 首次运行时检查
psutil.net_if_addrs()是否能正常返回,判断基础网络信息是否可读 - 避免在无管理员权限的 CMD 下运行——Windows 需要 SeNetworkStatisticsPrivilege 权限,普通用户可能拿不到完整数据
高频采集(
psutil.net_io_counters() 底层调用系统 API,Linux 走 /proc/net/dev,Windows 走 PDH,都不是零开销操作。实测在 2C4G 的云主机上,每 100ms 调一次,CPU 占用能到 8%–12%,远超预期。
监控节奏得按场景分档:
- 告警级监控:2–5 秒采样一次足够,速率波动看趋势,不是抓瞬时峰值
- 调试定位问题时才临时切到 200ms,并加
if __debug__:包裹,上线前删掉 - 如果用 asyncio,别在线程里反复调这个函数——它不是异步友好的,阻塞主线程
真要毫秒级观测,应该换 eBPF 或 libpcap 方案,psutil 不是干这个的
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











