在一项针对不同远程点音视频流探测和统计任务中,系统使用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')