前几天发现服务器上有几个zombie进程,搜索了一下(ps -ef | grep defunct),僵尸进程的父进程是以前写的python同步脚本。
仔细看了下代码,发现在这:
sub = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # other codes
对,父进程开启了子进程后,并无任何动作,子进程执行完成后成为一个僵尸进程。
解决方法很简单,父进程wait子进程即可,但因为标准输出和标准错误输出是管道方式(PIPE),直接使用wait()有可能会导致管道堵塞,python官方文档亦有以下叙述:
Warning This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.
官方建议适用communicate方法,于是修改代码如下:
sub = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out, err = sub.communicate()
另外一种修改方式,适用于不关心子进程返回结果的场景,可以将STDOUT和STDERR输出结果定向到/dev/dull去,再调用wait()即可,如下:
sub = subprocess.Popen(cmd, shell=True, stdout=open("/dev/null", "w"), stderr=subprocess.STDOUT) sub.wait()
因为需要子进程的处理信息,选用了第一种方法。重新启动python脚本,不再出现僵尸进程的问题了。