摘要
如果要判断某一脚本是否在运行,可以通过psutil库获取所有进程的cmdline,并判断指定的文件名是否在cmdline中。
目录
1.psutil库简介
2.检查代码及说明
2.1检查思路
2.2异常捕获
2.3执行方法
1.psutil库简介
psutil 是一个跨平台(Linux, Windows, macOS)的 Python 库,用于检索系统运行的进程和系统利用率(CPU、内存、磁盘等)的详细信息。这个模块可以帮助你获取系统资源和性能的数据,非常适合进行系统监控、调试和分析。
以下是 psutil 模块的一些主要功能:
- 获取进程信息:可以检索到系统中运行的进程列表,包括进程ID(PID)、进程名称、内存使用情况、CPU使用情况、进程的启动时间、运行状态、使用的命令行参数等。
- 获取系统信息:可以获取到系统的总体信息,比如操作系统版本、处理器信息、物理内存和交换内存的使用情况、系统运行时间等。
- 进程树:可以构建进程树,显示进程之间的父子关系。
- 网络统计:可以获取到进程的网络连接信息,包括发送和接收的数据量、连接的远程地址等。
- 用户统计:可以查看不同用户运行的进程以及它们对系统资源的使用情况。
- 磁盘使用情况:可以查看磁盘分区的使用情况,包括已使用空间、可用空间、挂载点等。
- 环境变量:可以获取进程的环境变量。
- 线程信息:可以获取进程中的线程信息,包括线程ID、线程名、线程的CPU使用情况等。
- 杀死进程:可以发送信号给进程,比如终止进程。
2.检查代码及说明
编写test.py文件,主要运行检查逻辑,检查的目标脚本是monitor.py文件,
其中monitor.py文件如下:
import time
def main():
while True:
print("-----monitor------")
time.sleep(10)
if __name__=="__main__":
main()
定时打印内容;
test.py文件如下:
import os
import psutil
def check_script_running(script_name):
for pid in psutil.pids():
try:
process=psutil.Process(pid)
cmdlines=list(process.cmdline())
process_name=process.name()
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
print("exception")
continue
if process_name != "python.exe":
continue
print(f"pid={pid}, name={process_name}, cmdline={cmdlines}")
for cur_ret in cmdlines:
if script_name in cur_ret:
print(f"check script pid={pid}")
return True
return False
def restart_script(script_path):
os.popen(f"python {script_path}")
if __name__=="__main__":
root_path=os.path.dirname(os.path.abspath(__file__))
check_file_name="monitor.py"
run_script_file=os.path.join(root_path, check_file_name)
if not check_script_running(check_file_name):
restart_script(run_script_file)
print(f"检测到{check_file_name}脚本未运行,已重启{run_script_file}")
else:
print(f"{check_file_name}脚本正常运行")
2.1检查思路
check_script_running函数中没有通过进程名来判断脚本是否运行,因为一台设备上可能同时运行了多个python脚本,这些脚本的进程名都是python.exe,无法判断指定脚本是否运行。而
psutil 库中的 getcmdline() 函数用于获取进程的命令行参数。这个函数返回一个字符串列表,其中包含了启动进程时传递给它的所有命令行参数。而在命令行参数中会有执行的python脚本的文件名,从而可以判断目标脚本是否在运行。
restart_script函数中使用了比较老旧的os.popen函数,而不是比较新的subprocess中的run和Popen函数,因为在调试过程中,发现subprocess的函数都会阻塞test.py所在的进程,由于monitor脚本中是死循环,这个进程会一直阻塞下去。这不符合业务要求,因此改用了非阻塞的os.popen函数。
2.2异常捕获
check_script_running在运行中,捕获了三个异常:
- psutil.NoSuchProcess: 这个异常发生在尝试访问一个不存在的进程时。这可能是因为进程的PID已经改变(例如,因为另一个进程使用了相同的PID),或者是因为进程已经终止并且PID不再有效。在Linux上,PID 1通常是 init 进程,它永远不会终止,因此永远不会遇到这个异常。
- psutil.AccessDenied: 当尝试访问一个进程但权限不足时,会抛出这个异常。例如,你可能尝试访问一个由其他用户拥有的进程,或者尝试访问一个受保护的系统进程。在某些情况下,你可能需要管理员权限来访问特定的进程信息。
- psutil.ZombieProcess: 这个异常发生在尝试访问一个僵尸进程时。僵尸进程是一个已经结束但仍然在进程表中占有一个条目的进程。在Unix-like系统中,僵尸进程会被父进程删除,但如果父进程没有正确处理僵尸进程(例如,父进程崩溃),那么僵尸进程可能会保留下来。
2.3执行方法
如果在vscode中运行test脚本,会发现每次运行,都会判断monior脚本未运行,然后重启,如下图
这是因为 VS Code 的 Python 扩展通常会在运行脚本时创建一个主进程,该主进程负责执行脚本,并且会在主进程结束后终止所有相关的子进程。
这种行为是为了确保在调试或运行过程中不会留下任何未终止的子进程,以避免资源泄漏或其他问题。
因此,要正确验证效果,需要在命令行中启动test.py脚本,如下图