python通过psutil判断当前脚本重复运行杀掉原进程

日期 2023年09月13日 16:29

分类 Python

标签 crontab

浏览 5975

字数统计: 2131(字)

crontab执行python脚本,如果周期内未执行完毕,会新开一个进程执行,会导致重复执行,大部分情况下需要避免这种情况

python中可以通过psutil获取所有进程信息,筛选出当前脚本,杀进程时需要先杀子进程,但子进程不能使用os.killpg(windows下运行.bat会有问题)

kill_exist_task 代码如下:

import os
import platform
import signal
import sys
import psutil

def kill_exist_task(filter_last_arg: str = ''):
    # 判断windows
    isWindows = platform.system() == "Windows"
    # py文件名
    py_file = sys.argv[0].split('/')[-1]
    if isWindows:
        py_file = sys.argv[0].split('\\')[-1]
    print("kill_exist_task", sys.argv, py_file, filter_last_arg)
    # 查找进程
    for proc in psutil.process_iter():
        cmd = []
        try:
            cmd = proc.cmdline()
        except Exception as e:
            pass
        proc_cmd = " ".join(cmd)
        # 匹配cmd进程: (D:\Python38\python.exe D:\scrap\grab.py 或 D:\Python38\python.exe grab.py 或 python.exe grab.py)
        if not (proc_cmd.__contains__("python") and proc_cmd.__contains__(py_file)):
            continue
        print(" -- 匹配到cmd: ", proc.pid, proc_cmd)
        # 查找相同基础并排除当前进程
        if os.getpid() == proc.pid:
            print(" -- 是当前进程: ", os.getpid(), proc.pid)
            continue
        print(" -- 不是当前进程: ", os.getpid(), proc.pid)
        # 过滤最后一个参数,如`python3 grab.py 2002`的 2002 (如需过滤其他参数,自行调整)
        if (not filter_last_arg) or (filter_last_arg and cmd[-1] == filter_last_arg):
            print(" -- 筛选出进程: py_file=%s,filter_last_arg=%s,pid=%s,cmd=%s" % (py_file, filter_last_arg, proc.pid, proc_cmd))
            try:
                # 终止子进程(可能通过shell或其他方式调起其他独立进程)
                pp = psutil.Process(proc.pid)
                for sub in pp.children(recursive=True):
                    print(" -- 终止子进程: %s %s" % (sub.name(), sub.pid))
                    # 子进程不能使用os.killpg(windows下运行`.bat`会有问题)
                    sub.terminate()
                    sub.kill()
                # 终止当前进程
                proc.terminate()
                proc.kill()
                os.killpg(proc.pid, signal.SIGKILL)
                print(" -- 终止主进程: terminate %s" % proc.pid)
            except Exception as e:
                pass
    print('kill_exist_task done')