[Python]记psutil.Process类使用注意事项

[Python]记psutil.Process类使用注意事项

💡 原文中文,约3200字,阅读约需8分钟。
📝

内容提要

文章介绍了在Python项目中使用psutil模块时遇到的问题和解决方法。作者在一个CI平台项目中使用psutil模块控制客户机的命令行操作,但发现当客户端断开连接时,整个进程会自动终止。通过排查发现是psutil模块中的一个bug导致的,经过修改代码逻辑后问题得到解决。作者还提到要查看psutil文档是否有相关说明,如果没有可以考虑向psutil做贡献。

🔎

延伸解读

psutil.Process(None) 的意外行为

文章通过测试发现,当向 psutil.Process() 传入 None 时,它会返回当前主进程的 Process 对象,而不是抛出异常或返回空。这意味着如果代码中未检查参数是否为 None,就可能误操作主进程。作者在调试时打印出 pid 与当前程序一致,才确认了这一行为。

terminate() 误杀主进程的后果

由于 psutil.Process(None) 获取到的是主进程,调用 terminate() 会直接终止当前程序。作者在终端测试中看到进程以 exit code 143 结束,对应 SIGTERM 信号。这解释了为何客户端断开连接时,整个服务端进程会意外退出。

防御性编程:检查 child_id 是否为 None

修复方案是在获取子进程前先判断 session 中的 child_pid 是否为 None,只有非 None 时才调用 psutil.Process()。这样避免了传入 None 导致误获取主进程。作者修改代码逻辑后,问题不再出现,说明简单的空值检查能有效防止此类错误。

文档与贡献的后续思考

作者计划查阅 psutil 官方文档,确认是否已说明 Process(None) 的行为。如果文档未提及,考虑向 psutil 项目贡献代码或文档,以帮助其他开发者避免类似陷阱。这体现了对开源社区的回馈意识,也提醒读者遇到未明确的行为时可主动完善文档。

❓

Q&A

psutil.Process() 传入 None 会有什么后果?

当 psutil.Process() 的参数为 None 时,它会获取当前主进程的 pid,而不是报错或返回空。如果随后调用 terminate(),就会终止主进程,导致程序退出。

为什么客户端断开连接后我的整个 Python 进程会被终止?

在 disconnect 事件处理中,如果 session 中的 child_pid 为 None,psutil.Process(None) 会获取到主进程的 pid,然后调用 terminate() 就会终止主进程,导致整个程序退出。

如何修复 psutil.Process 错误终止主进程的问题?

在调用 psutil.Process() 之前,先检查 child_id 是否为 None,只有不为 None 时才获取子进程对象。这样可以避免误将主进程当作子进程终止。

psutil 模块的安装命令是什么?

安装 psutil 模块的命令是 pip install psutil。

在 CI 平台项目中,psutil 被用来做什么?

在 CI 平台项目中,psutil 被用来管理通过 SSH 连接客户机后启动的子进程,例如在客户端断开连接时终止对应的子进程。

如何调试 psutil.Process 获取到错误 pid 的问题?

可以使用 print() 输出 psutil.Process() 返回的对象以及 session 中保存的 child_pid,对比两者是否一致,从而发现 psutil.Process(None) 获取了主进程 pid 的问题。

🏷️

标签

➡️

继续阅读