如何并行运行Python子进程以监控并终止外部程序?
解决Python中并行运行外部程序与监控脚本的问题
问题根源
你之前的两种方法失败的原因:
- 连续使用
subprocess.call:call是阻塞式调用,会等待第一个进程(program 1)完全结束后才会启动第二个监控脚本,但program 1无法自行终止,导致监控脚本永远无法运行。 - 直接用
Popen创建进程列表:虽然启动了两个并行进程,但监控脚本无法获取program 1的进程ID(PID),也就无法在检测完成后终止它;且未做后续的进程存活检查,可能主脚本退出后监控进程也被意外终止。
解决方案
方案一:将监控逻辑整合到主脚本(推荐)
无需单独的监控脚本,直接在主脚本中启动program 1后,并行执行监控逻辑:
import subprocess import time # 启动program 1,获取进程对象 proc_program1 = subprocess.Popen( cmd, cwd=current_working_directory, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT ) # 配置监控参数 LOG_FILE = "/path/to/your/output.log" # 替换为program 1完成时会输出到日志的特定标识,比如"Task finished successfully" COMPLETION_MARKER = "任务完成标识" # 循环监控 while proc_program1.poll() is None: # 检查program 1是否仍在运行 try: with open(LOG_FILE, "r") as f: if COMPLETION_MARKER in f.read(): # 终止program 1,先尝试温和终止,不行则强制杀死 proc_program1.terminate() # 如果terminate无效,改用kill:proc_program1.kill() print("检测到program 1完成,已终止进程") break except Exception as e: print(f"读取日志文件出错: {str(e)}") time.sleep(60) # 每60秒检查一次 # 等待进程彻底结束,释放资源 proc_program1.wait()
方案二:使用独立监控脚本(需传递PID)
如果必须保留独立的监控脚本,需要将program 1的PID传递给它,让监控脚本能定位并终止目标进程:
主脚本代码
import subprocess # 启动program 1 proc_program1 = subprocess.Popen( cmd, cwd=current_working_directory, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT ) # 启动监控脚本,传入program 1的PID和日志路径 monitor_script = "/home/.../Documents/pythonScriptFolder/monitor.py" monitor_cmd = [ "python3", monitor_script, str(proc_program1.pid), "/path/to/your/output.log" ] subprocess.Popen( monitor_cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT ) # 等待program 1结束 proc_program1.wait()
监控脚本(monitor.py)代码
import os import sys import time def main(): if len(sys.argv) != 3: print("用法: python monitor.py <program1_pid> <log_file_path>") sys.exit(1) program1_pid = int(sys.argv[1]) log_file = sys.argv[2] COMPLETION_MARKER = "任务完成标识" # 替换为实际的完成标识 while True: # 先检查program 1是否还存活 try: os.kill(program1_pid, 0) # 发送0信号仅用于检测进程是否存在 except OSError: print("program 1已终止,监控结束") break # 读取日志检测完成状态 try: with open(log_file, "r") as f: if COMPLETION_MARKER in f.read(): os.kill(program1_pid, 15) # SIGTERM终止进程 # 无效则改用SIGKILL:os.kill(program1_pid, 9) print("检测到完成,已终止program 1") break except Exception as e: print(f"读取日志出错: {str(e)}") time.sleep(60) if __name__ == "__main__": main()
内容的提问来源于stack exchange,提问作者Nicolas B
相关产品推荐
相关产品推荐

