将模块“subprocess”与timeou一起使用

2024-04-23 06:10:10 发布

您现在位置:Python中文网/ 问答频道 /正文

下面是Python代码,用于运行返回其stdout数据的任意命令,或对非零退出代码引发异常:

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程序中,实现超时的最简单方法是什么?


Tags: and数据代码命令cmd进程stderrstdout
3条回答

在Python3.3+中:

from subprocess import STDOUT, check_output

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

output是一个字节字符串,包含命令的合并stdout和stderr数据。

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

我删除了shell=True,因为它经常被不必要地使用。如果cmd确实需要的话,您可以将其添加回去。如果添加shell=True,即如果子进程生成自己的子进程,check_output()可以比超时指示的时间晚很多返回,请参见Subprocess timeout failure

通过3.2+子流程模块的^{}后台端口,Python 2.x上提供了超时功能。

我对底层细节不太了解,但考虑到 python 2.6api提供了等待线程和 终止进程,在单独的 线?

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的任何内容 不支持。

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

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

相关问题 更多 >