[python] subprocess.terminate()残留进程的处理方法

在一项针对不同远程点音视频流探测和统计任务中,系统使用ubuntu kylin通过contrab的方式定期探测分散的不同远程点传送回中心的音视频流过程中,发现系统在运行一段时间后就会残留的ffprobe进程越来越多,导致系统速度变慢卡死 ps -ef | grep ffprobe 查看了一下,系统中残留这大把没有返回的进程,对于没有返回的进程,我的处理方式是:

p = subprocess.Popen(probeUrl, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
t_begining = time.time()
seconds_passed = 0                        
while True:                                
    # move on in case returning                                
    if p.poll() is not None:                                        
        break                                
        seconds_passed = time.time() - t_begining
        # 如果30秒内没有返回就关闭进程                                
        if  seconds_passed > 30:                                        
            p.terminate()                                  
            raise TimeoutError('ffprobe time out in 30 seconds')                                
        time.sleep(0.1)

在实际使用过程中发现之所以有残留的原因是这样的,由于subprocess.Popen调用的是bash,probeUrl = "/home/jl/ffmpeg-2.8.5/ffprobe '"+ streamUrl +"'",系统首先启动了一个bash进程,再由bash进程启动ffprobe,从而生成了一个子进程,一共是两个进程,而p.terminate()只是结束了启动的bash,并没有将ffprobe进程结束,这样结束并抛出异常后,30秒内没有返回的ffprobe就挂死在系统中,一直处于等待返回的状态。每天都会有这样的进程产生,日积月累下来,系统自然出现问题。改进的方法是采用psutil包,逻辑是先关闭bash产生的所有ffprobe进行,然后再关闭bash。

def kill_child_processes(parent_pid, sig=signal.SIGKILL):
        try:
                p = psutil.Process(parent_pid)
        except psutil.error.NoSuchProcess:
                return
        child_pid = p.get_children(recursive=True)
        for pid in child_pid:
                os.kill(pid.pid, sig)
                
# 如果30秒内没有返回就关闭进程                                
if  seconds_passed > 30:   
kill_child_processes(p.pid)                                       
p.terminate()                                  
raise TimeoutError('ffprobe time out in 30 seconds')




你可能感兴趣的:(python,ubuntu,ffprobe)