如何在stdout/stderr无活动时终止子进程
我正在通过一个Python脚本运行一个程序(现在使用的是os.system
)。不过,有时候这个程序会在某个地方卡住,如果在一定时间内没有输出到标准输出(stdout)或标准错误(stderr),我想把它杀掉。简单的超时设置不太管用,因为这个程序通常需要运行很长时间(可能是几个小时到几天),而且有时候它会在还没完成之前就卡住。
看起来subprocess.Popen
是个不错的选择,但我还没找到一个好的例子来说明怎么做。我还想把标准输出和标准错误写入一个文件。
根据一些例子,我在考虑像这样做:
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 个回答
2
为了完整起见,这里是我最终使用的代码,利用了建议的 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
2
试着用 signal.alarm
来设置一个定时器,每当接收到一行数据后就启动这个定时器。然后通过处理 SIGALRM
信号,检查自从上一次接收到数据以来是否已经过了太长时间。