You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下如何监控Python Popen子进程并在任一进程结束后终止其余进程

问题描述

我编写了一段Python代码,可在不同Shell窗口中同时运行带有不同参数的同一Python脚本,代码如下:

import subprocess
import shlex

if __name__ == '__main__':

    arg_list = ["gnome-terminal -- python3 teste.py ./get_data/datasets/training_out.xlsx 140.10.61.1 0 2 102 4 OUTPUT 0 632 MEMORY 0 3885 1 0",
            "gnome-terminal -- python3 teste.py ./get_data/datasets/training_out2.xlsx 140.10.61.1 0 2 102 1 OUTPUT 0 272 MEMORY 0 3885 1 1",
            "gnome-terminal -- python3 teste.py ./get_data/datasets/training_in.xlsx 140.10.61.1 0 2 102 2 INPUT 0 632 MEMORY 0 3885 1 2",
            "gnome-terminal -- python3 teste.py ./get_data/datasets/training_in2.xlsx 140.10.61.1 0 2 102 2 INPUT 0 272 MEMORY 0 3885 1 3",
            "gnome-terminal -- python3 teste.py ./get_data/datasets/training_in3.xlsx 140.10.61.1 0 2 102 1 INPUT 0 274 MEMORY 0 3885 1 4"             
            ]

    p1 = subprocess.Popen(shlex.split(arg_list[0]))

    p2 = subprocess.Popen(shlex.split(arg_list[1]))

    p3 = subprocess.Popen(shlex.split(arg_list[2]))

    p4 = subprocess.Popen(shlex.split(arg_list[3]))

    p5 = subprocess.Popen(shlex.split(arg_list[4]))

但我需要监控这些子进程,当任一子进程执行完成后,终止其余所有运行中的子进程。我尝试使用.wait()和.poll()方法,但它们仅在gnome terminal启动后就改变状态,而非在终端内的脚本执行结束时变化,请问在Linux下该如何实现这种监控?

解决方案

方法一:利用gnome-terminal的--wait参数

gnome-terminal提供了--wait参数,该参数会让终端窗口保持打开状态,直到内部执行的命令完全结束。此时subprocess启动的gnome-terminal进程的结束状态会与内部teste.py脚本的结束状态同步,这样就能通过.wait()或.poll()正确监控脚本的执行完成事件。

修改后的代码示例:

import subprocess
import shlex
import signal

if __name__ == '__main__':
    # 为每个gnome-terminal命令添加--wait参数
    arg_list = [
        "gnome-terminal --wait -- python3 teste.py ./get_data/datasets/training_out.xlsx 140.10.61.1 0 2 102 4 OUTPUT 0 632 MEMORY 0 3885 1 0",
        "gnome-terminal --wait -- python3 teste.py ./get_data/datasets/training_out2.xlsx 140.10.61.1 0 2 102 1 OUTPUT 0 272 MEMORY 0 3885 1 1",
        "gnome-terminal --wait -- python3 teste.py ./get_data/datasets/training_in.xlsx 140.10.61.1 0 2 102 2 INPUT 0 632 MEMORY 0 3885 1 2",
        "gnome-terminal --wait -- python3 teste.py ./get_data/datasets/training_in2.xlsx 140.10.61.1 0 2 102 2 INPUT 0 272 MEMORY 0 3885 1 3",
        "gnome-terminal --wait -- python3 teste.py ./get_data/datasets/training_in3.xlsx 140.10.61.1 0 2 102 1 INPUT 0 274 MEMORY 0 3885 1 4"             
    ]

    # 启动所有进程并保存进程对象
    processes = []
    for cmd in arg_list:
        proc = subprocess.Popen(shlex.split(cmd))
        processes.append(proc)
    
    # 监控进程状态,任一进程结束则终止其余进程
    try:
        while processes:
            for idx, proc in enumerate(processes):
                # 检查进程是否已结束
                if proc.poll() is not None:
                    print(f"进程 {idx} 执行完成,正在终止其余进程...")
                    # 终止所有未结束的进程
                    for p in processes:
                        if p.poll() is None:
                            p.send_signal(signal.SIGTERM)
                    processes = []
                    break
    except KeyboardInterrupt:
        # 处理手动中断,清理所有进程
        for p in processes:
            if p.poll() is None:
                p.send_signal(signal.SIGTERM)

方法二:直接监控teste.py进程

如果不想依赖gnome-terminal的参数,可以直接追踪实际运行的teste.py进程。通过psutil库可以方便地查找和监控进程状态,当任一teste.py进程结束时,终止剩余的teste.py进程及对应的终端窗口。

步骤说明

  1. 先安装psutil库:pip install psutil
  2. 启动终端进程后,获取所有teste.py的PID
  3. 循环监控这些PID的运行状态,一旦有进程结束,立即终止剩余进程

示例代码:

import subprocess
import shlex
import psutil
import os
import signal

def get_teste_pids():
    """获取当前运行的所有teste.py进程PID"""
    pids = []
    for proc in psutil.process_iter(['pid', 'cmdline']):
        try:
            cmdline = proc.info['cmdline']
            # 判断是否是目标teste.py进程
            if cmdline and 'python3' in cmdline[0] and 'teste.py' in cmdline[1]:
                pids.append(proc.info['pid'])
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    return pids

if __name__ == '__main__':
    arg_list = [
        "gnome-terminal -- python3 teste.py ./get_data/datasets/training_out.xlsx 140.10.61.1 0 2 102 4 OUTPUT 0 632 MEMORY 0 3885 1 0",
        "gnome-terminal -- python3 teste.py ./get_data/datasets/training_out2.xlsx 140.10.61.1 0 2 102 1 OUTPUT 0 272 MEMORY 0 3885 1 1",
        "gnome-terminal -- python3 teste.py ./get_data/datasets/training_in.xlsx 140.10.61.1 0 2 102 2 INPUT 0 632 MEMORY 0 3885 1 2",
        "gnome-terminal -- python3 teste.py ./get_data/datasets/training_in2.xlsx 140.10.61.1 0 2 102 2 INPUT 0 272 MEMORY 0 3885 1 3",
        "gnome-terminal -- python3 teste.py ./get_data/datasets/training_in3.xlsx 140.10.61.1 0 2 102 1 INPUT 0 274 MEMORY 0 3885 1 4"             
    ]

    # 启动所有终端进程
    term_processes = []
    for cmd in arg_list:
        proc = subprocess.Popen(shlex.split(cmd))
        term_processes.append(proc)
    
    # 获取初始的teste.py进程PID列表
    initial_teste_pids = get_teste_pids()
    print(f"正在监控的teste.py进程PID: {initial_teste_pids}")

    try:
        while initial_teste_pids:
            # 遍历检查每个PID的状态
            for pid in initial_teste_pids[:]:
                if not psutil.pid_exists(pid):
                    print(f"teste.py进程 {pid} 执行完成,正在终止其余进程...")
                    # 终止剩余的teste.py进程
                    for p in initial_teste_pids:
                        if psutil.pid_exists(p):
                            os.kill(p, signal.SIGTERM)
                    # 终止所有终端进程
                    for term_proc in term_processes:
                        if term_proc.poll() is None:
                            term_proc.send_signal(signal.SIGTERM)
                    initial_teste_pids = []
                    break
    except KeyboardInterrupt:
        # 手动中断时清理所有进程
        for pid in initial_teste_pids:
            if psutil.pid_exists(pid):
                os.kill(pid, signal.SIGTERM)
        for term_proc in term_processes:
            if term_proc.poll() is None:
                term_proc.send_signal(signal.SIGTERM)

内容的提问来源于stack exchange,提问作者guilhermeguim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 15:57:18