Python进程树管理:如何避免僵尸进程

引言

在开发需要管理子进程的应用程序时(例如任务调度系统、自动化测试平台等),我们常会遇到需要终止整个进程树的需求。直接使用kill -9虽然暴力有效,但可能导致资源泄漏或状态不一致等问题。如何在Python中实现多进程任务的生命周期管理?本文将通过完整的代码案例+原理解析+可视化流程图,带你掌握三个关键技能:

  1. 创建多线程任务并监控输出
  2. 捕获进程树关系
  3. 分级终止策略(优雅退出→强制终止)

一、多线程脚本(task.py):工作线程的产生 ,子进程

import os
import threading


def print_msg():
    for count in range(100000):
        current_thread = threading.current_thread()
        print(f"task:{
     os.getpid()} {
     current_thread.name} {
     current_thread.ident} count:{
     count}", flush=True)


if __name__ == '__main__':
    threads = []
    for i in range(3):
        thread = threading.Thread(
            target=print_msg,
            name=f"task_thread-{
     i + 1}"
        )
        threads.append(thread)
        thread.start()

    # 等待所有线程完成
    for thread in threads:
        thread.join()

    print("所有工作线程执行完毕")  # 如果外部终止,这里不会输出

关键点解析

  • 每个线程执行10,000次计数打印,flush=True确保实时输出
  • 主线程会等待所有工作线程结束(但实际需要外部终止)
  • 线程共享进程PID,体现多线程特性

二、进程监控脚本(runner.py):子进程的创建与输出捕获 ,父进程

import os
import subprocess

if __name__ == '__main__':
    try:
        # 使用上下文管理器启动子进程
        with subprocess.Popen(["python3", "task.py"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, encoding='utf-8') as process:
            # 记录子进程pid到文件
            with open("pid.txt", "w") as f:
                f.write(str(process.pid))

            # 实时读取子进程输出
            while True:
                line = process.stdout.readline()
                # 如果没有下两面这句,kill的又是task_pid,那么task进程会变成僵尸进程,无法kill
                # if not line and process.poll() is not None: # 输出结束且子进程已退出
                #     break  
                print(f"runner:{
     os.getpid()} popen:{
     process.pid} {
     line.strip()}")

    except KeyboardInterrupt:
        print
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值