python僵尸进程回收

python僵尸进程回收,第1张

python僵尸进程回收

文章目录
  • 1.背景
  • 2.思路
  • 3.僵尸进程回收方法
  • 4.调用方法

1.背景

在Python中使用 p = subprocess.Popen 执行 shell命令时,如果不使用 p.wait() ,就会产生僵尸进程,对于僵尸进程可以采用 os.wait(),os.waitpid()等方式回收,但是os.wait()是阻塞的,所以一般采用os.waitpid() 回收指定僵尸进程。

2.思路
0.在主进程下启动一个线程,主管僵尸进程回收工作
1.先获取主进程下的所有子进程列表
2.再获取linux系统的所有僵尸进程列表
3.列表取交集,即是当前主进程下的僵尸子进程
4.然后对主进程下的僵尸子进程计入字典,key是僵尸子进程pid,value是计入子进程的时间戳
5.计算字典记录中僵尸子进程存活时间
6.如果超过阈值,则主动回收该子进程
7.循环回收
3.僵尸进程回收方法
# -*- coding: utf-8 -*-
"""
Author: tanggaomeng
date:   2021/11/20
Description:    
    回收僵尸子进程
        1.只能回收主进程下面的僵尸子进程,对孙子、重孙子僵尸进程无法回收
        2.如果想回收孙子、重孙子僵尸进程,需在子、孙子进程添加回收僵尸进程代码
"""
import os
import time
import errno
import commands
import logging

logging.basicConfig(format="%(asctime)s|%(levelname)s|%(filename)s:%(lineno)s|%(message)s", level=logging.DEBUG)

# record the zombie process dictionary
CHILD_ZOMBIE_DICT = {}
# allow zombie process time to live: unit seconds
ZOMBIE_TIME_TO_LIVE = 30


def get_child_zombie(parent_pid):
    """
    get zombie child process that exceed the threshold
    record the zombie process dictionary: {"zombie process pid": "timestamp"}
    :param parent_pid: the current main process
    :return: the zombie process pid
    """
    # 1.get a list of all child process of the current main process
    child_pid_cmd = "ps -ef | awk '{if($3==%s) print $2}' | sort | uniq"
    child_pid_list = commands.getoutput(child_pid_cmd % (parent_pid))
    child_pid_list = child_pid_list.split("n")
    logging.info("main process [%s]: 1-child_pid_list: %s" % (parent_pid, child_pid_list))
    # 2.get a list of all zombie processes on linux system
    node_zombie_cmd = "ps -A -ostat,pid | grep -e '^[Zz]' | awk '{print $2}'"
    node_zombie_list = commands.getoutput(node_zombie_cmd)
    node_zombie_list = node_zombie_list.split("n")
    logging.info("main process [%s]: 2-node_zombie_list: %s" % (parent_pid, node_zombie_list))
    # 3.the intersection of the lists is the zombie child process under the current main process
    child_zombie_list = list(set(child_pid_list).intersection(node_zombie_list))
    logging.info("main process [%s]: 3-child_zombie_list: %s" % (parent_pid, child_zombie_list))

    global CHILD_ZOMBIE_DICT
    logging.info("main process [%s]: 4-CHILD_ZOMBIE_DICT: %s" % (parent_pid, CHILD_ZOMBIE_DICT))
    if child_zombie_list:
        for child_zombie_pid in child_zombie_list:
            time_value = float(CHILD_ZOMBIE_DICT.get(child_zombie_pid, 0))
            time_now = time.time()
            if time_value:
                # calculation time
                time_diff = round(time_now - time_value, 2)
                # recycling time exceeds the threshold child process
                if time_diff > ZOMBIE_TIME_TO_LIVE:
                    CHILD_ZOMBIE_DICT.pop(child_zombie_pid)
                    return child_zombie_pid
            else:
                CHILD_ZOMBIE_DICT[child_zombie_pid] = time_now
                return 0
    else:
        # if there is no zombie process under the current main process, clear the record
        CHILD_ZOMBIE_DICT.clear()
        return 0


def wait_child(ppid):
    while True:
        try:
            # get the pid of the zombie child process that exceeds the threshold under the main process
            child_zombie_pid = get_child_zombie(ppid)
            if child_zombie_pid:
                logging.info("main process [%s]: 5-child_zombie_pid: %s" % (ppid, child_zombie_pid))
                child_pid, status = os.waitpid(int(child_zombie_pid), os.WNOHANG)
                if child_pid == 0:
                    # no child process was immediately available
                    continue
                return_code = status >> 8
                logging.info(
                    "main process [%s]: child process: %s exit with return code: %s" % (ppid, child_pid, return_code))
            else:
                continue
        except OSError as e:
            if e.errno == errno.ECHILD:
                logging.info("main process [%s]: no child process that need to wait" % (ppid))
            else:
                logging.error("main process [%s] OSError: %s" % (ppid, e))
        except Exception as e:
            logging.exception("main process [%s] Exception: %s" % (ppid, e))
        finally:
            time.sleep(5)

4.调用方法
# -*- coding: utf-8 -*-
"""
Author: tanggaomeng
date:   2021/11/21
Description:    

"""

import os
import time
import threading
from recycling_zombie_processes import wait_child


def main():
    for i in range(0, 1000):
        time.sleep(5)


if __name__ == '__main__':
    # recycling zombie processes
    ppid = os.getpid()
    thread = threading.Thread(target=wait_child, args=(ppid,))
    thread.start()
	main()

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5572197.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存