Python子进程超时?

时间:2015-03-20 17:38:24

标签: python subprocess

我有一个运行另一个命令的脚本,等待它完成,记录stdout和stderr并根据返回代码执行其他操作。这是代码:

p = subprocess.Popen(command, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
o, e = p.communicate()
if p.returncode:
    # report error

# do other stuff

我遇到的问题是如果command需要很长时间才能运行,其他任何操作都不会完成。如果没有错误没有完成,则不会报告可能的错误以及需要发生的其他事情。如果花费太长时间,它基本上不会超过p.communicate()。有时这个命令可能需要几个小时(甚至更长时间)才能运行,有时可能需要5秒钟。

我错过了什么或做错了什么?

2 个答案:

答案 0 :(得分:1)

根据位于here的文档,可以肯定地说您的代码正在等待子流程完成。

如果你需要去做其他事情'等你的时候可以创建一个循环:

while p.poll():
    # 'other things'
    time.sleep(0.2)

选择一个合理的睡眠时间,以确定您希望python唤醒和检查子流程以及执行其他事情的频率。

答案 1 :(得分:0)

Popen.communicate在返回任何内容之前等待进程完成。因此,它不适合任何长时间运行的命令;甚至更少,如果子进程可以挂起等待输入,比如提示输入密码。


如果要将命令的输出捕获到变量中,则stderr=subprocess.PIPE, stdout=subprocess.PIPE仅需 。如果您输出到终端是正常的,那么您可以删除这两个;甚至使用subprocess.call代替Popen。另外,如果你没有为子进程提供输入,那么根本不要使用stdin=subprocess.PIPE,而是直接从null设备引导(在Python 3.3+中你可以使用{{3在Python< 3.3中使用stdin=open(os.devnull, 'rb')


如果你也需要内容,那么你可以自己阅读p.communicate()p.stdout并输出到终端,而不是调用p.stderr,但它有点复杂,因为很容易使程序死锁 - 虚拟方法会尝试从子进程'stdout读取,而子进程想要写入stderr。对于这种情况,有2种补救措施:

  • 您可以使用stdin=subprocess.DEVNULL轮询stdoutstderr以查看先准备就绪并从中读取的内容

  • 或者,如果您不关心stdoutstderr合并为一个, 您可以使用select.select将stderr流重定向到stdout流:stdout=subprocess.PIPE, stderr=subprocess.STDOUT;现在所有输出都来到p.stdout,您可以在循环中轻松读取并输出块,而不必担心死锁:


如果stdout,stderr将是 huge ,你也可以将它们假设为Popen中的文件;比方说,

stdout = open('stdout.txt', 'w+b')
stderr = open('stderr.txt', 'w+b')

p = subprocess.Popen(..., stdout=stdout, stderr=stderr)
while p.poll() is None:
    # reading at the end of the file will return an empty string
    err = stderr.read()  
    print(err)
    out = stdout.read()
    print(out)
    # if we met the end of the file, then we can sleep a bit
    # here to avoid spending excess CPU cycles just to poll;
    # another option would be to use `select`
    if not err and not out:  # no input, sleep a bit
        time.sleep(0.01)