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

Python 为什么即使子进程已完成,Popen.poll()仍返回None的返回代码?,python,windows,subprocess,Python,Windows,Subprocess,我有一些在Windows上运行的Python代码,生成一个子进程并等待它完成。子进程的行为不好,因此脚本会进行非阻塞的spawn调用,并在一旁监视该进程。如果满足某个超时阈值,它将终止进程的运行,假设进程已脱离轨道 在某些不可复制的情况下,生成的子流程将消失,而观察者例程将无法发现这一事实。它将一直监视,直到超过超时阈值,尝试终止子进程并获取错误,然后退出 是什么原因导致观察者进程无法检测到子进程已离开的事实?为什么调用Popen.poll()? 我用于生成和观察过程的代码如下: import

我有一些在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\u code=handle.poll()
的调用将返回
None
,而不是返回代码。我知道这个过程已经完全消失了——我可以看到它不再存在于任务管理器中。我知道这个过程在达到超时值之前很久就消失了。

你能举一个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

子流程对象上的轮询方法似乎工作得不太好。 我以前也有同样的问题,而我是产卵一些线程来做一些工作。
我建议您使用多处理模块。

Popen.poll无法按预期工作如果stdout被其他东西捕获,您可以检查这部分代码”,stdout=subprocess.PIPE“

这是一个随机模拟命令,恐怕我不能说更多了。每1000次执行中就有1次这样的情况发生,我一直无法可靠地重现这种情况。额外的括号和
temp_cmdline
变量都要感谢我在发布之前所做的一些清理,但这是一个很好的收获!)
cmdline
是一个列表。确定。这很好,因为我所做的最后一个子处理是针对一个基于随机性的预测工具的GUI包装。它是用python创建的吗?如果是,您使用的是什么库?PyMC?还有,你的模拟要花多长时间?在进行模拟时,您的代码是否需要运行其他程序?因为您可能只是能够调用wait()命令而不是轮询。如果它是一个基于python的模拟命令,也许您可以使用线程。还有一件事,你试过把睡眠时间从60秒减少到2秒吗?第三方命令是基于C的,我没有它的来源。而且它有挂断的习惯,这就是为什么实现了轮询解决方案。我试试减少睡眠时间。谢谢我现在正在用这个解决方案进行重构,但我希望能对不稳定的
Popen.poll()
行为做出解释。