为什么即使子进程已完成,Popen.poll()也会返回None的返回码?

时间:2012-11-08 22:01:43

标签: python windows subprocess

我有一些在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而不是返回代码。我知道这个过程完全消失了 - 我可以看到任务管理器中已经不存在了。我知道这个过程在达到超时值之前很久就消失了。

3 个答案:

答案 0 :(得分:1)

您能举例说明您的cmdline变量吗?还会产生什么样的子流程?

我在测试脚本上运行它,使用以下命令调用批处理文件:

ping -n 151 127.0.0.1>nul
  • 睡眠150秒

它工作正常。

可能是您的子进程未正确终止。另外,尝试将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”