【发布时间】:2015-10-07 07:46:02
【问题描述】:
这是我的代码,它启动一个子进程,等待它结束并返回标准输出,或者发生超时并引发异常。常用的是print(Run('python --version').execute())
class Run(object):
def __init__(self, cmd, timeout=2*60*60):
self.cmd = cmd.split()
self.timeout = timeout
self._stdout = b''
self.dt = 10
self.p = None
def execute(self):
print("Execute command: {}".format(' '.join(self.cmd)))
def target():
self.p = Popen(self.cmd, stdout=PIPE, stderr=STDOUT)
self._stdout = self.p.communicate()[0]
thread = Thread(target=target)
thread.start()
t = 0
while t < self.timeout:
thread.join(self.dt)
if thread.is_alive():
t += self.dt
print("Running for: {} seconds".format(t))
else:
ret_code = self.p.poll()
if ret_code:
raise AssertionError("{} failed.\nretcode={}\nstdout:\n{}".format(
self.cmd, ret_code, self._stdout))
return self._stdout
else:
print('Timeout {} reached, kill task, pid={}'.format(self.timeout, self.p.pid))
self.p.terminate()
thread.join()
raise AssertionError("Timeout")
问题在于以下情况。我启动的进程会产生更多的子进程。因此,当达到超时时,我用self.p.terminate() 杀死主进程(我使用我的类启动的那个),孩子们还在,我的代码挂在self._stdout = self.p.communicate()[0] 线上。如果我手动终止所有子进程,则会继续执行。
当我杀死整个进程树而不是 self.p.terminate() 时,我尝试了解决方案。
如果主进程自己完成并且它的子进程自己存在,这也不起作用,我没有能力找到并杀死它们。但是他们阻止了self.p.communicate()。
有没有办法有效解决这个问题?
【问题讨论】:
-
它正在将管道句柄泄漏给孙进程。如果您没有源代码控制,我不知道如何防止这种情况发生。但是您可以尝试通过
DEBUG_PROCESS将其作为调试器运行并查找CREATE_PROCESS_DEBUG_EVENT来存储子进程句柄。然后就可以终止整个进程树了。 -
如果你打电话给
output = subprocess.check_output(command, timeout=timeout)会发生什么? -
@J.F.Sebastian,我认为它会挂起,因为
check_output假设在终止进程后第二次调用communicate将成功(第 610-612 行)。由于管道句柄泄露给其他进程,read()将再次阻塞在读取器线程中,但这次join没有超时。最好只终止子进程。
标签: python windows python-3.x subprocess stdout