我有一些在Windows上运行的Python代码,它生成一个子进程并等待它完成。子进程表现不佳,因此脚本会进行非阻塞的spawn调用并在旁边监视进程。如果满足某个超时阈值,它将导致进程终止,假设它已经消失了。
在某些不可重现的情况下,生成的子进程将消失,观察程序将不会发现这一事实。它将继续观察直到超时阈值通过,尝试终止子进程并获得错误,然后退出。
可能导致子进程无法被观察者进程检测到的事实是什么?为什么通过调用Popen.poll()
我用来产生和观察过程的代码如下:
import subprocess
import time
def nonblocking_subprocess_call(cmdline):
print 'Calling: %s' % (' '.join(cmdline))
p = subprocess.Popen(cmdline, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return p
def monitor_subprocess(handle, timeout=1200):
start_time = time.time()
return_code = 0
while True:
time.sleep(60)
return_code = handle.poll()
if return_code == None:
# The process is still running.
if time.time() - start_time > timeout:
print 'Timeout (%d seconds) exceeded -- killing process %i' % (timeout, handle.pid)
return_code = handle.terminate()
# give the kill command a few seconds to work
time.sleep(5)
if not return_code:
print 'Error: Failed to kill subprocess %i -- return code was: %s' % (handle.pid, str(return_code))
# Raise an error to indicate that the process was hung up
# and we had to kill it.
raise RuntimeError
else:
print 'Process exited with return code: %i' % (return_code)
break
return return_code
我所看到的是,在进程消失的情况下,第15行的return_code = handle.poll()
调用返回None
而不是返回代码。我知道这个过程完全消失了 - 我可以看到任务管理器中已经不存在了。我知道这个过程在达到超时值之前很久就消失了。
答案 0 :(得分:1)
您能举例说明您的cmdline变量吗?还会产生什么样的子流程?
我在测试脚本上运行它,使用以下命令调用批处理文件:
ping -n 151 127.0.0.1>nul
它工作正常。
可能是您的子进程未正确终止。另外,尝试将sleep命令更改为time.sleep(2)。
在过去,我发现这比睡眠时间更长(特别是如果你的子进程是另一个python进程)。
另外,我不确定你的脚本是否有这个,但是在else:语句中,你有一个额外的括号。
else:
#print 'Process exited with return code: %i' % (return_code))
# There's an extra closing parenthesis
print 'Process exited with return code: %i' % (return_code)
break
为什么在join语句中调用全局temp_cmdline:
print 'Calling: %s' % (' '.join(temp_cmdline))
我不确定是否从列表变量temp_cmdline解析cmdline,或者是否从空格上拆分的字符串创建temp_cmdline。无论哪种方式,如果你的cmdline变量是一个字符串,那么打印它会更有意义吗?
print 'Calling: %s' % cmdline
答案 1 :(得分:1)
poll方法似乎不太好用。 我曾经产生同样的问题,而我正在产生一些线程来做一些工作。 我建议你使用多处理模块。
答案 2 :(得分:0)
如果 stdout 被其他东西捕获,Popen.poll 不会按预期工作,您可以检查取出这部分代码“, stdout=subprocess.PIPE”