超时使用模块“subprocess”

以下是运行任意命令返回stdout数据的Python代码,或在非零退出代码上引发异常:

proc = subprocess.Popen(
    cmd,
    stderr=subprocess.STDOUT,  # Merge stdout and stderr
    stdout=subprocess.PIPE,
    shell=True)

communicate用于等待进程退出:

stdoutdata, stderrdata = proc.communicate()

subprocess进程模块不支持超时 - 杀死运行超过X秒的进程的能力 - 因此, communicate可能需要永远运行。

在Windows和Linux上运行的Python程序中实现超时的最简单方法是什么?


在Python 3.3+中:

from subprocess import STDOUT, check_output

output = check_output(cmd, stderr=STDOUT, timeout=seconds)

output是包含命令的合并标准输出stderr数据的字节字符串。

proc.communicate()方法不同,此代码在问题文本中指定的非零退出状态引发CalledProcessError

我已经删除了shell=True因为它经常被不必要地使用。 如果cmd确实需要它,您可以随时添加它。 如果你添加shell=True ,如果子进程产生自己的后代; check_output()返回的时间可能比timeout指示晚得多,请参阅子进程超时失败。

超时功能通过提供关于Python 2.x的subprocess32的3.2+子模块的反向移植。


我对低层次的细节知之甚少; 但是,考虑到在Python 2.6中,API提供了等待线程和终止进程的能力,那么在独立线程中运行进程又该如何呢?

import subprocess, threading

class Command(object):
    def __init__(self, cmd):
        self.cmd = cmd
        self.process = None

    def run(self, timeout):
        def target():
            print 'Thread started'
            self.process = subprocess.Popen(self.cmd, shell=True)
            self.process.communicate()
            print 'Thread finished'

        thread = threading.Thread(target=target)
        thread.start()

        thread.join(timeout)
        if thread.is_alive():
            print 'Terminating process'
            self.process.terminate()
            thread.join()
        print self.process.returncode

command = Command("echo 'Process started'; sleep 2; echo 'Process finished'")
command.run(timeout=3)
command.run(timeout=1)

这个片段在我的机器中的输出是:

Thread started
Process started
Process finished
Thread finished
0
Thread started
Process started
Terminating process
Thread finished
-15

可以看出,在第一次执行时,进程正确完成(返回码0),而在第二次执行中进程终止(返回码-15)。

我没有在Windows中测试; 但除了更新示例命令之外,我认为它应该起作用,因为我没有在文档中发现任何说thread.join或process.terminate不受支持的东西。


使用threading.Timer类可以简化jcollado的答案:

import shlex
from subprocess import Popen, PIPE
from threading import Timer

def run(cmd, timeout_sec):
    proc = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE)
    timer = Timer(timeout_sec, proc.kill)
    try:
        timer.start()
        stdout, stderr = proc.communicate()
    finally:
        timer.cancel()

# Examples: both take 1 second
run("sleep 1", 5)  # process ends normally at 1 second
run("sleep 5", 1)  # timeout happens at 1 second
链接地址: http://www.djcxy.com/p/54685.html

上一篇: Using module 'subprocess' with timeout

下一篇: How to read all message from queue using stomp library in Python?