首页/新闻资讯/正文详情

psutil 进程遍历优化实战:`process_iter(attrs=...)` 预取 API 的用法、原理与性能提升

发布时间:2026/9/23 20:12:49 来源:云帆数科 栏目:资讯中心
psutil 进程遍历优化实战:`process_iter(attrs=...)` 预取 API 的用法、原理与性能提升
psutil 进程遍历优化实战process_iter(attrs...)预取 API 的用法、原理与性能提升【免费下载链接】psutilCross-platform lib for process and system monitoring in Python项目地址: https://gitcode.com/gh_mirrors/ps/psutil本指南以 psutil 官方博客 Improved process_iter() 为主体系统讲解 psutil 5.3.0 引入的process_iter(attrs..., ad_value...)预取 API如何告别繁琐的try/except样板代码一次性批量抓取进程属性并深入源码剖析其内部缓存与oneshot()加速机制。读完本文你将掌握用 3 行代码安全遍历全部进程并收集属性、正确处理权限拒绝与进程消失竞态以及结合推导式写出简洁高性能进程监控代码的全部技巧。背景遍历进程收集属性的旧模式在 psutil 5.3.0 之前遍历所有进程并收集属性是一件需要大量样板代码的事。原因在于process_iter()返回的Process实例存在两个天然的不稳定因素进程可能在你访问它的瞬间消失进程退出、PID 被回收导致抛出psutil.NoSuchProcess某些进程需要提升权限才能访问如其他用户的进程导致抛出psutil.AccessDenied。因此每一次属性查询都必须用try/except包裹 import psutil for proc in psutil.process_iter(): ... try: ... pinfo proc.as_dict(attrs[pid, name]) ... except (psutil.NoSuchProcess, psutil.AccessDenied): ... pass ... else: ... print(pinfo) ... {pid: 1, name: systemd} {pid: 2, name: kthreadd} {pid: 3, name: ksoftirqd/0}正如博客作者强调的这段try/except并非装饰性的摆设而是避免竞态条件race condition的必要防护。进程列表是在迭代瞬间的快照进程随时可能退出不加防护的代码会在高并发系统上随机崩溃。新 APIprocess_iter(attrs..., ad_value...)psutil 5.3.0 为process_iter()新增了两个参数attrs和ad_value把上述样板代码压缩到了极致。循环体变成了 import psutil for proc in psutil.process_iter(attrs[pid, name]): ... print(proc.info) ... {pid: 1, name: systemd} {pid: 2, name: kthreadd} {pid: 3, name: ksoftirqd/0}语义要点如下传入了attrs后process_iter()内部会为每个Process实例一次性预取pre-fetch指定的属性迭代过程中消失的进程会被静默跳过不再抛NoSuchProcess会触发AccessDenied的属性被赋值为ad_valuead_value默认是None也可以显式指定一个哨兵值如N/Afor p in psutil.process_iter([name, username], ad_valueN/A): print(p.name(), p.username())注意即使预取时属性访问失败并回退到了ad_value后续方法调用如上面的p.name()、p.username()依然可以正常工作只是返回的是回退值而非真实值。参数详解attrs与ad_value的完整语义在当前的源码中process_iter()与Process.as_dict()共享同一套参数语义见 psutil/init.py 与 Process.as_dict()attrs一个字符串集合list、tuple、set、frozenset均可元素为Process类公开只读属性的名字例如[cpu_times, name, memory_info]。若传入非集合类型如字符串会抛出TypeError若包含不存在的属性名会抛出ValueError。attrsNone默认不预取process_iter()照常逐个产出Process实例等价于旧行为。attrsProcess.attrs检索全部进程信息作者在源码 docstring 中特别标注 slow因为属性全量拉取开销最大。Process.attrs是定义在 psutil/init.py 的一个frozenset由dir(Process)自动推导得出排除了send_signal、terminate、kill、wait、as_dict、parent等非信息型方法。ad_value预取过程中某个属性抛出AccessDenied或ZombieProcess时代替异常返回的值默认None。它只影响预取结果不影响进程本身的产出。异常处理策略源码级事实as_dict()的预取循环体现了精确的异常分级策略AccessDenied与ZombieProcess→ 回退为ad_valueNoSuchProcess→不会被吞掉而是向上冒泡由process_iter()主循环捕获并将该 PID 从内部缓存移除NotImplementedError→ 默认静默跳过该属性仅当用户显式指定了attrs且该属性不可用时才抛出这是为了在老旧或特殊平台上不因个别功能缺失而整体崩溃。这些行为在 tests/test_process.py 中有完整的测试覆盖ad_value在AccessDenied与ZombieProcess下生效、NoSuchProcess上抛、NotImplementedError的默认跳过 / 显式要求则抛出两种分支以及非法attrs类型触发TypeError/ValueError的校验。源码剖析预取机制到底做了什么理解了用法后我们深入到 psutil/init.py 的实现看看这背后发生了什么。1. 进程实例缓存表_pmapprocess_iter()维护着一个全局的内部缓存表_pmapPID →Process实例。每次调用时将当前 PID 集合pids()与缓存中的 PID 集合做差集识别出新出现的 PID 与已消失的 PID已消失的从缓存中移除新出现的创建Process实例加入缓存同时处理 PID 复用_pids_reused场景刷新被复用的实例最终按 PID 排序后逐个yield。因此同一进程的Process实例在多次调用间是复用的而不是每次重建。缓存可以通过process_iter.cache_clear()手动清空。2. 预取与_use_prefetch装饰器当传入attrs时主循环对每个实例执行proc._prefetch {} # 清空上一次迭代的缓存 proc._ad_value _SENTINEL if attrs is not None: proc._prefetch proc.as_dict(attrsattrs, ad_valuead_value) proc._ad_value ad_value yield proc即调用一次as_dict()把全部属性提前算好存入Process._prefetch字典。而Process类中几乎所有只读方法name()、cmdline()、cpu_times()、memory_info()、username()、num_threads()、open_files()、net_connections()等都被一个名为_use_prefetch的装饰器包裹psutil/init.pydef _use_prefetch(method): functools.wraps(method) def wrapper(self, *args, **kwargs): if not args and not kwargs: try: return self._prefetch[method.__name__] except KeyError: pass return method(self, *args, **kwargs) return wrapper这就是预取的本质方法被调用时只要_prefetch字典里已有同名键且无额外参数就直接返回缓存值不再发起任何新的系统调用。所以p.name()与p.info[name]在预取场景下读取的是同一份数据。3.Process.info的现状重要博客原文2017 年展示的是proc.info的访问方式。在**当前仓库版本psutil 8.0.0**中Process.info属性仍然可用但已被标记为deprecated弃用访问它会触发DeprecationWarning提示改用直接方法调用如p.name()而非p.info[name]。由于_use_prefetch缓存的存在直接方法调用同样能拿到预取值所以推荐写法是for p in psutil.process_iter(attrs[name, username]): print(p.name(), p.username()) # 命中预取缓存零额外系统调用4. 僵尸进程与消失进程的兜底预取阶段as_dict()内部遇到ZombieProcess会回退为ad_value而主循环中若进程整个消失NoSuchProcess该 PID 会从_pmap中移除并被静默跳过。这解释了消失的进程被静默跳过、权限受限的属性返回ad_value这一对核心承诺的底层来源。性能原理等价于每个进程一次oneshot()博客指出process_iter(attrs[...])在性能上等价于对每个进程调用一次Process.oneshot()上下文管理器。这与as_dict()的实现直接对应——看 as_dict() 的源码retdict {} names attrs or sorted(valid_names) with self.oneshot(): for name in names: ...也就是说预取本身就是在一个oneshot()块内完成的。oneshot()psutil/init.py的工作原理是进程的许多属性如name()、ppid()、uids()、create_time()、memory_info()、cpu_times()等在底层共享同一次系统调用或同一个/proc文件。进入oneshot()后psutil 会激活cpu_times、memory_info、ppid、uids等方法的记忆化缓存并调用平台层的oneshot_enter()让平台实现把共享的系统调用结果缓存起来退出时统一清理。对比旧模式在循环里逐个调用proc.as_dict()或逐个方法每次调用都可能重新读取/proc/pid/stat等文件而预取模式把同一进程的所有属性在一次系统调用批次内取完。属性越多节省的重复系统调用越显著——这正是比在循环里逐个调用方法快得多的根源。关于oneshot()的深入原理可参考配套博客 One shot, twice as fast。实战推导式终于可以干净地使用去掉异常样板代码后列表/字典推导式终于可以优雅地工作了。博客给出了最经典的场景——找出当前用户拥有的全部进程 import getpass from pprint import pprint as pp pp([(p.pid, p.info[name]) for p in psutil.process_iter(attrs[name, username]) if p.info[username] getpass.getuser()]) [(16832, bash), (19772, ssh), (20492, python)]在当前版本中等价写法避免已弃用的p.info是 import getpass from pprint import pprint as pp pp([(p.pid, p.name()) for p in psutil.process_iter(attrs[name, username]) if p.username() getpass.getuser()])p.name()与p.username()都命中预取缓存循环体内不再有任何异常风险和多余的系统调用。再举两个衍生实战场景按内存占用列出 Top 进程import psutil procs [ (p.info[pid], p.info[name], p.info[memory_info].rss) for p in psutil.process_iter(attrs[pid, name, memory_info]) ] procs.sort(keylambda x: x[2], reverseTrue) for pid, name, rss in procs[:10]: print(f{pid:7} {rss / 1024 / 1024:8.1f} MB {name})统计每个用户开启的进程数import psutil from collections import Counter counter Counter( p.info[username] for p in psutil.process_iter(attrs[username], ad_value?) ) print(counter)这里的ad_value?保证即使有进程的username查询触发AccessDenied统计也不会中断。注意事项与版本演进基于当前仓库源码使用该 API 时需注意以下几点空attrs是歧义的process_iter(attrs[])在 8.0.0 中会触发DeprecationWarning其余空集合如空元组、空 set会触发UserWarning——因为as_dict()会把空集合解析为全部属性语义含糊应显式改用attrsProcess.attrsad_value使用is判定Process._is_ad_value()通过值就是ad_value本身value is self._ad_value来判断回退因此不要传入可变对象作为ad_value后再原地修改它ZombieProcess仍会被产出主循环对ZombieProcess的处理是照常yield僵尸进程在psutil中仍是有效的Process实例其属性在预取阶段以ad_value兜底预取只发生一次每次process_iter()迭代产出实例时都会清空并重建_prefetch所以循环体内不要再调用as_dict()重新预取as_dict()内部自带oneshot()重复使用反而损失性能方法级缓存不冲突_use_prefetch与memoize_when_activated是两层独立缓存_use_prefetch只在process_iter(attrs...)预取时生效二者互不干扰。总结process_iter(attrs..., ad_value...)是 psutil 进程遍历 API 的一次重要升级维度旧模式新模式样板代码每个属性访问都要try/except零异常处理性能属性分散读取重复系统调用as_dict()内oneshot()批量预取竞态安全依赖人工捕获异常消失进程静默跳过、受限属性回退ad_value代码表达难以使用推导式列表/字典推导式干净可用该 API 自 5.3.0 引入后一直保留至今当前仓库为 8.0.0且被 tests/test_process.py 的完整测试所守护。编写进程监控、进程管理或系统巡检脚本时process_iter(attrs..., ad_value...)应作为遍历进程的首选姿势相关变更的完整列表可查阅 HISTORY.rst 中的 5.3.0 章节。【免费下载链接】psutilCross-platform lib for process and system monitoring in Python项目地址: https://gitcode.com/gh_mirrors/ps/psutil创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

手机连打印机保姆级教程:3步搞定API变更痛点
手机连打印机保姆级教程:3步搞定API变更痛点

手机连打印机保姆级教程:3步搞定API变更痛点 版本升级后 API 全变了?别慌,这份保姆级教程带你避坑。 很多人卡在蓝牙协议和权限配置上,浪费半天时间。 今天直接上干货,对比主流方案,代码全给你。 方案定位:谁在统治手机打印领域… · 2026/9/23 20:12:49

为什么国内厂商卖的服务器配置低价格贵?
为什么国内厂商卖的服务器配置低价格贵?

厂商典型配置价格(月)带宽/流量特点腾讯云轻量2核2G / 50-60GB SSD≈45-52元4-5Mbps,300-500GB流量国内访问优秀,稳定,备案方便阿里云轻量2核2G / 40-50GB SSD≈40-60元3-5Mbps生态最大,活动多百度智能云 B… · 2026/9/23 20:12:43

udhcpc底层原理详解:3个步骤搞定嵌入式网络配置保姆级教程
udhcpc底层原理详解:3个步骤搞定嵌入式网络配置保姆级教程

udhcpc底层原理详解:3个步骤搞定嵌入式网络配置保姆级教程 刚把别人博客里的 udhcpc 命令复制到 Linux 终端,回车后一片沉默,或者报错 No lease, failing ?别急,这绝不是你的硬件问题,而是你根本不知道… · 2026/9/23 20:12:35

Yii 2 Gii 代码生成器实战指南:从启用模块到自动生成完整 CRUD 应用
Yii 2 Gii 代码生成器实战指南:从启用模块到自动生成完整 CRUD 应用

后端Web框架 【免费下载链接】yii2 Yii 2: The Fast, Secure and Professional PHP Framework 项目地址: https://gitcode.com/gh_mirrors/yi/yii2 点击查看 免费下载 Gii 是 Yii 2 官方提供的可视化代码生成器,能够根据数据库表结构自动生成 Active Re… · 2026/9/23 20:49:11

Harness 可靠性文档(RELIABILITY.md)编写指南:如何用仓库本地证据证明系统可重启、可诊断、可回归
Harness 可靠性文档(RELIABILITY.md)编写指南:如何用仓库本地证据证明系统可重启、可诊断、可回归

【免费下载链接】learn-harness-engineering Harness engineering beginner tutorial, from 0 to 1 项目地址: https://gitcode.com/gh_mirrors/le/learn-harness-engineering 点击查看 免费下载 本文以 docs/ja/resources/openai-advanced/repo-template/docs/REL… · 2026/9/23 20:49:11

男女性别检测数据集:VOC+YOLO双格式9769张图开箱即训
男女性别检测数据集:VOC+YOLO双格式9769张图开箱即训

简介:这份数据集面向计算机视觉与目标检测方向的开发者与学生,提供男女性别检测所需的图像与标注文件,可直接用于训练YOLO、Faster R-CNN等模型。数据集合计9769张jpg图片,并配套Pascal VOC格式xml与YOLO格式txt标注,共… · 2026/9/23 20:49:10

BP三维点目标成像:机载下视雷达成像的MATLAB仿真与避坑指南
BP三维点目标成像:机载下视雷达成像的MATLAB仿真与避坑指南

简介:三维雷达成像MATLAB资源面向机载雷达下视成像应用,围绕点目标反投影(Back Projection)重建算法展开,适合雷达信号处理、合成孔径雷达及遥感测绘方向的学生、研究者或工程师用以理解三维成像原理。压缩包内仅有1个… · 2026/9/23 20:49:00

AI本地部署全栈调优:从BIOS到PyTorch的性能闭环
AI本地部署全栈调优:从BIOS到PyTorch的性能闭环

1. 这不是“调个设置”那么简单:为什么AI软件在你电脑上跑得慢、报错多、甚至根本启动不了玩AI,先别急着下载Stable Diffusion或Ollama,更别一上来就冲去GitHub找模型。我带过三十多个本地部署AI项目的团队,见过太多人花三天时间调… · 2026/9/23 20:48:54

3步搞定微云网页版登录:一文搞懂报错背后的真相
3步搞定微云网页版登录:一文搞懂报错背后的真相

3步搞定微云网页版登录:一文搞懂报错背后的真相 打开浏览器输入 weiyun.com,页面加载出那一行红色的报错信息,或者卡在“正在验证...”的转圈动画上不动,你是不是也想砸键盘?这种时候,满屏的英文 StackTrace… · 2026/9/23 20:48:41

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码