最近用subprocess模块的Popen函数开启子进程,运行flask框架时出现一个问题,那就是调用subprocess模块的脚本运行结束后,在其fork出的子进程中运行的flask框架并未关闭,这就导致在开发阶段关闭该子进程十分麻烦,经过一番查找测试,通过使用wait()方法阻塞父进程或捕获关闭信号(ctrl+c)后关闭子进程便可轻易解决.
首先我们来看看出现的问题,这是启动两个flask框架的脚本(至于python解释器要用绝对路径的方式写,那是因为subprocess.Popen函数就相当于在终端新开了一个窗口,即便你的脚本已经在指定虚拟环境或指定解释器下运行了,但是subprocess.Popen函数开启的子进程的运行环境和父进程无关,所以不指定解释器,直接用python启动程序的话,就相当于使用系统默认的python解释器运行程序)
#!/usr/bin/python
#-*- coding: utf-8 -*-
import subprocess
manage = subprocess.Popen("/home/lyz/.virtualenvs/videoframework_py2/bin/python2.7 video_server/video_server.py", shell=True)
yolo3 = subprocess.Popen("/home/lyz/.virtualenvs/python3_video/bin/python3.5 algorithm_server/algorithm_server.py ",shell=True)
这是脚本运行结束后查找python相关进程的情况
可以看到,当python脚本运行结束后,我在另外一个终端查找python相关进程,该脚本启动的两个flask框架仍在运行,使得每次关闭子进程时还要查找进程号,再用kill -9 进程号的方法杀死子进程,十分麻烦,于是,使用子进程对象的wait()方法,阻塞父进程,从而在强制退出时使父进程报错,让父进程和子进程一同结束.这是改动之后的脚本.
#!/usr/bin/python
#-*- coding: utf-8 -*-
import subprocess
import signal
import sys
manage = subprocess.Popen("/home/lyz/.virtualenvs/videoframework_py2/bin/python2.7 video_server/video_server.py", shell=True)
yolo3 = subprocess.Popen("/home/lyz/.virtualenvs/python3_video/bin/python3.5 algorithm_server/algorithm_server.py ",shell=True)
ret=yolo3.wait()
这是运行之后的结果,可以看到使用ctrl+c关闭脚本后,该脚本启动的两个flask框架也同时关闭了.
假如觉得上面的方法不够优雅,可以使用python的signal模块,捕获关闭信号(ctrl+c),再调用kill()或者terminate() 方法关闭子进程.代码如下:
#!/usr/bin/python
#-*- coding: utf-8 -*-
import subprocess
import signal
import sys
manage = subprocess.Popen("/home/lyz/.virtualenvs/videoframework_py2/bin/python2.7 video_server/video_server.py", shell=True)
yolo3 = subprocess.Popen("/home/lyz/.virtualenvs/python3_video/bin/python3.5 algorithm_server/algorithm_server.py ",shell=True)
# ret=yolo3.wait()
def signal_handler(signal, frame):
# manage.kill()
# yolo3.kill()
manage.terminate()
yolo3.terminate()
sys.exit(0)
signal.signal(signal.SIGINT,signal_handler)
while True:
pass
这是运行之后的结果,可以看到使用ctrl+c关闭脚本后,该脚本启动的两个flask框架同样也同时关闭了,且没有任何报错.