Python中如何监控Windows程序并自动重启,遇到bug怎么解决?
这种情况不固定出现,有时候运行几次就出现了,有时候运行几十次才出现,各位大佬求解
Python中如何监控Windows程序并自动重启,遇到bug怎么解决?
import psutil
import subprocess
import time
import logging
from datetime import datetime
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('monitor.log'),
logging.StreamHandler()
]
)
class ProcessMonitor:
def __init__(self, process_name, exe_path):
"""
:param process_name: 要监控的进程名(如: notepad.exe)
:param exe_path: 程序可执行文件完整路径
"""
self.process_name = process_name.lower()
self.exe_path = exe_path
self.process = None
def is_process_running(self):
"""检查进程是否在运行"""
for proc in psutil.process_iter(['name']):
try:
if proc.info['name'].lower() == self.process_name:
return proc
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return None
def start_process(self):
"""启动程序"""
try:
self.process = subprocess.Popen(self.exe_path)
logging.info(f"已启动进程: {self.process_name}")
return True
except Exception as e:
logging.error(f"启动进程失败: {e}")
return False
def monitor(self, check_interval=5):
"""监控主循环"""
logging.info(f"开始监控进程: {self.process_name}")
while True:
try:
current_proc = self.is_process_running()
if not current_proc:
logging.warning(f"进程 {self.process_name} 未运行,正在重启...")
if not self.start_process():
logging.error("重启失败,等待下次检查")
else:
# 检查进程状态
try:
status = current_proc.status()
if status == psutil.STATUS_ZOMBIE:
logging.warning(f"进程 {self.process_name} 处于僵尸状态,准备重启...")
current_proc.terminate()
time.sleep(2)
self.start_process()
except:
pass
time.sleep(check_interval)
except KeyboardInterrupt:
logging.info("监控程序已停止")
break
except Exception as e:
logging.error(f"监控出错: {e}")
time.sleep(check_interval)
# 使用示例
if __name__ == "__main__":
# 配置要监控的程序
monitor = ProcessMonitor(
process_name="notepad.exe", # 进程名
exe_path="C:\\Windows\\System32\\notepad.exe" # 程序路径
)
# 开始监控,每10秒检查一次
monitor.monitor(check_interval=10)
核心要点:
- 进程检测:用
psutil遍历系统进程,匹配进程名 - 状态监控:检查进程是否存在,以及是否处于僵尸状态
- 自动重启:进程消失时用
subprocess.Popen()重新启动 - 异常处理:捕获权限异常、进程异常等
- 日志记录:所有操作记录到日志文件,方便排查
遇到bug的解决方法:
- 权限问题:用管理员权限运行监控脚本
- 路径问题:确保
exe_path是完整路径且存在 - 进程名匹配:Windows进程名带
.exe后缀 - 资源占用:合理设置检查间隔,避免CPU过高
一句话建议: 用psutil监控进程状态,subprocess实现重启,加日志记录方便排查。
我没有做过相关的,猜测是下述原因:
假设出错的 pid 为 x,那么获取 pids 时,x 在其中,但是之后进程 x 结束了(可能刚获取完就结束也可能遍历时结束),所以报错:找不到进程 x.
加个 try 吧
不好意思,新人,刚学会用语法上图片。。。
import os,psutil,time,signal
ProList = []
i = 0
ProcessName = “1.exe"
ProgramPath = r"E:\test\1.exe”
#检测并启动进程
def main():
print(psutil.pids())
for pid in psutil.pids():
p = psutil.Process(pid)
ProList.append(str(p.name()))
if p.name() == ProcessName:
kill(pid)
print(“111”)
def kill(pid):
try:
print(“killing Server…”)
os.kill(pid, signal.SIGTERM)
time.sleep(6)
print(“Restart Server Success…”)
os.startfile(ProgramPath)
print(pid)
except e:
print(“没有%s 进程” % pid)
if name==“main”:
while True:
main()
i = i+1
print(i)
time.sleep(3)
Traceback (most recent call last):
File “D:\python\lib\site-packages\psutil<a target=”_blank" href=“http://_pswindows.py” rel=“nofollow noopener”>_pswindows.py", line 635, in wrapper
return fun(self, *args, **kwargs)
File “D:\python\lib\site-packages\psutil<a target=”_blank" href=“http://_pswindows.py” rel=“nofollow noopener”>_pswindows.py", line 821, in create_time
return cext.proc_create_time(self.pid)
ProcessLookupError: [Errno 3] No such process
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “D:\python\lib\site-packages\psutil<a target=”_blank" href=“http://init.py” rel=“nofollow noopener”>init.py", line 368, in _init
self.create_time()
File “D:\python\lib\site-packages\psutil<a target=”_blank" href=“http://init.py” rel=“nofollow noopener”>init.py", line 699, in create_time
self._create_time = self._proc.create_time()
File “D:\python\lib\site-packages\psutil<a target=”_blank" href=“http://_pswindows.py” rel=“nofollow noopener”>_pswindows.py", line 640, in wrapper
raise NoSuchProcess(self.pid, self._name)
psutil._exceptions.NoSuchProcess: psutil.NoSuchProcess process no longer exists (pid=11812)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “jiankong.py”, line 40, in <module>
main()
File “jiankong.py”, line 12, in main
p = psutil.Process(pid)
File “D:\python\lib\site-packages\psutil<a target=”_blank" href=“http://init.py” rel=“nofollow noopener”>init.py", line 341, in init
self._init(pid)
File “D:\python\lib\site-packages\psutil<a target=”_blank" href=“http://init.py” rel=“nofollow noopener”>init.py", line 381, in _init
raise NoSuchProcess(pid, None, msg)
psutil._exceptions.NoSuchProcess: psutil.NoSuchProcess no process found with pid 11812
先确定你的 NoSuchProcess 是出在比较的时候,还是在 Kill 的时候.
kill 完了,然后也重启启动了,之后就出现这样的
在上一次打印的 pids 中 这个不存在的进程 pid 还是有的
好的谢谢,我试一下加个 try ;确实在上一次打印 pids 时,存在这个 pid ;然后就出错了;
windows 批处理干这活很简单的。。。<br> off<br><br>:start<br>ping -n 3 127.0.0.1>nul<br>tasklist | find /I "notepad.exe"<br>if %errorlevel%==0 goto start<br>::start notepad.exe<br>start cmd /c "notepad.exe"<br>goto start<br>
for pid in psutil.pids():
p = psutil.Process(pid)
for: 你获取了一个 pids 的列表, 这时当时的一个 pids 是一个状态, 并不代表着你在循环时 pids 列表里的 pid 会一直存在.
问题复现如下:
>>> a = psutil.pids()
>>> a
[0, 4, 396, 516, 612, 764, 772, 860, 916, 332, 464, 512, 972, 1112, 1164, 1296, 1564, 1784, 1908, 1968, 2064, 2148, 2192, 2280, 2412, 2556, 2564, 2572, 2580, 2588, 2668, 2708, 2788, 2796, 2804, 2872, 2884, 2900, 2460, 3236, 3780, 4376, 5352, 5684, 2684, 2180, 6060, 488, 2616, 1244, 2692, 4356, 5972, 3516, 5960, 1984, 3452, 6496, 6628, 7812, 7872, 7976, 8052, 8076, 8096, 8120, 8148, 8160, 1744, 7508, 7720, 7744, 8072, 2376, 7436, 8220, 9088, 9128, 8508, 8412, 12188, 3484, 3680, 5928, 5348, 7588, 16352, 5872, 604, 15716, 7028, 16168, 12880, 15220, 11432, 14988, 100, 15564, 12856, 16796, 7064, 17356, 16028, 10380, 14980, 9864, 14776, 16064, 17028, 728, 9792, 8024, 15304, 14760, 17196, 13072, 12244, 13712, 9876, 16876, 11956, 6556, 11608, 13080, 16892, 15456, 8156, 11664, 12792, 6248, 14940, 16188, 15324, 1000, 16212, 7752, 13520, 12328, 4724]
>>> type (a)
<class ‘list’>
# 这里手工 KILL 掉 14988 进程, 模拟被其它程序关闭…etc
>>> psutil.Process(14988)
Traceback (most recent call last):
File “C:\Python3\lib\site-packages\psutil<a target=”_blank" href=“http://_pswindows.py” rel=“nofollow noopener”>_pswindows.py", line 636, in wrapper
return fun(self, *args, **kwargs)
File “C:\Python3\lib\site-packages\psutil<a target=”_blank" href=“http://_pswindows.py” rel=“nofollow noopener”>_pswindows.py", line 822, in create_time
return cext.proc_create_time(self.pid)
ProcessLookupError: [Errno 3] No such process
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “C:\Python3\lib\site-packages\psutil<a target=”_blank" href=“http://init.py” rel=“nofollow noopener”>init.py", line 428, in _init
self.create_time()
File “C:\Python3\lib\site-packages\psutil<a target=”_blank" href=“http://init.py” rel=“nofollow noopener”>init.py", line 754, in create_time
self._create_time = self._proc.create_time()
File “C:\Python3\lib\site-packages\psutil<a target=”_blank" href=“http://_pswindows.py” rel=“nofollow noopener”>_pswindows.py", line 641, in wrapper
raise NoSuchProcess(self.pid, self._name)
psutil.NoSuchProcess: psutil.NoSuchProcess process no longer exists (pid=14988)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “<pyshell#5>”, line 1, in <module>
psutil.Process(14988)
File “C:\Python3\lib\site-packages\psutil<a target=”_blank" href=“http://init.py” rel=“nofollow noopener”>init.py", line 401, in init
self._init(pid)
File “C:\Python3\lib\site-packages\psutil<a target=”_blank" href=“http://init.py” rel=“nofollow noopener”>init.py", line 441, in _init
raise NoSuchProcess(pid, None, msg)
psutil.NoSuchProcess: psutil.NoSuchProcess no process found with pid 14988
>>>
我实现的方式更简单…
我直接获取需要监视进程的 PID,如果进程已经退 PID 肯定不存在返回的值一定小于 0
对诶
但是你怎么获取到那个 pid 呢,重启之后 pid 改变了
直接隔段时间就读取一次 windows 的开机时间不是更好么?不需要固定跑一个 process
看不清
你为什么一定要获得 PID 呢… 你直接判定进程是否存在不就行了… 换个思路来嘛
这方法太野鸡了
po 主的问题答案很简单,因为你得到的 PID 是“刚刚存在的进程的 PID ”,过一会儿就可能没有了。尤其是,当你枚举到那个 PID 之前走过 kill 的代码路径的话,你需要等待好几秒,这非常容易导致刚刚那个 PID 的进程已经没有了。
接下来说说 2 个之前的错误:
#6 kill 被 try-catch 包裹,不可能在 console 输出该异常
#13 一个进程结束之后,如果该进程的内核对象已经被释放,则它的 PID 可以被重用。不能这样去判断一个进程是否已经结束。
另外从代码我实在猜不出来 po 主的代码有什么“有意义”的用途,如果我没理解错,这段代码是想:
循环结束所有的 1.exe ,并用对每个结束的 1.exe 都启动一个 E:\test\1.exe 代替之。循环这样做,导致每个重新启动的 1.exe 都会被再次 kill 并启动。
如果总共有 k 个 1.exe ,那么一个 1.exe 能存活不超过 6k+O(1) 秒。
考虑只有一个 1.exe 的情况,我看不出为什么要不断杀掉、等 6 秒再重启 1.exe 。
- -你 kill 里的 pid 没有重新获取啊。。程序重启 pid 变了
如果要监控的程序是你自己的,可以通过进程间通信实现,不用这么麻烦
我的意思是,获取 a.exe 的 PID,不是直接取 PID,你就算被 b.exe 占了 PID 又有什么影响呢…

