将模块“子进程”与超时一起使用

新手上路,请多包涵

这是运行任意命令返回其 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 程序中实现超时的 最简单 方法是什么?

原文由 Sridhar Ratnakumar 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 260
2 个回答

在 Python 3.3+ 中:

 from subprocess import STDOUT, check_output

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

output 是一个字节字符串,包含命令的合并标准输出、标准错误数据。

check_output 引发 CalledProcessError 问题文本中指定的非零退出状态不同于 proc.communicate() 方法。

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

超时功能在 Python 2.x 上可用,通过 subprocess32 3.2+ 子进程模块的反向端口。

原文由 jfs 发布,翻译遵循 CC BY-SA 4.0 许可协议

我对底层细节了解不多;但是,考虑到在 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 的内容。

原文由 jcollado 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题