如果stdout / stderr中没有活动,如何杀死子进程

时间:2013-03-17 13:30:37

标签: python subprocess

我正在从python脚本运行程序(目前使用os.system)。但是,有时程序会挂起,如果在一定时间间隔后没有写入stdout或stderr,我想杀死它。程序上的简单超时将无法工作,因为此代码通常会运行很长时间(数小时到数天),有时它会在它还有很长的路要走之前挂起。

似乎subprocess.Popen是要走的路,但我还没有找到一个如何做到这一点的好例子。我还想将stdout / stderr写入文件。

基于一些例子我正在考虑这样的事情:

p = Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None)

while True:
    line = p.stdout.readline()
    outfile.write(line)
    # save current time or something, compare to time of
    # previous loop, if larger than timeout, kill process

但我不确定如何实现时间循环,以及如何确保while在进程最终自行终止(并且不挂起)时不会永远运行。任何指针都将非常感激。

2 个答案:

答案 0 :(得分:1)

尝试使用signal.alarm在收到每一行后设置一个计时器,然后通过检查自上一行以来是否经过了太多时间来处理SIGALRM

答案 1 :(得分:1)

为了完整性,请参阅我最终使用的代码,并使用建议的signal.alarm

import time
import shlex
import subprocess

logfile = open(log, 'w', 1)
# cmd is command to run
args = shlex.split(cmd)   # tokenise args list
p = subprocess.Popen(args, shell=False, bufsize=0, stdin=None,
                     stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

def _handler(signum, frame):
    print('Timeout of %s min reached, stopping execution' % timeout)
    p.kill()
    time.sleep(30)  # to ensure no ghost process is left running
    raise RuntimeError('Timeout')

signal.signal(signal.SIGALRM, _handler)
try:
    while True:
        signal.alarm(int(timeout))
        inline = p.stdout.readline()
        if not inline:
            break
        logfile.write(inline)
        signal.alarm(0)
except RuntimeError:
    logfile.close()
    return 0

p.communicate()   # wait for process to finish, get return code
logfile.close()
return p.returncode