首页 > 编程问答 >使用带有超时的模块“子进程”

使用带有超时的模块“子进程”

时间:2024-07-25 09:15:01浏览次数:17  
标签:python multithreading timeout subprocess

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

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

communicate 用于等待进程退出:

stdoutdata, stderrdata = proc.communicate()

模块不支持超时——能够终止运行时间超过 X 秒的进程——因此, subprocess 可能需要永远运行。 communicate 在 Python 中实现超时的最简单方法是什么

程序应该在 Windows 和 Linux 上运行吗? simplest way to implement timeouts in a Python program meant to run on Windows and Linux?


import subprocess
import threading

def command_with_timeout(cmd, timeout=10):
    """Runs a command with a timeout, returns stdout, stderr and exit code"""

    def run_command(cmd):
        """Target function for the thread, runs the command and sets results"""
        try:
            process = subprocess.Popen(
                cmd,
                stderr=subprocess.STDOUT,
                stdout=subprocess.PIPE,
                shell=True
            )
            global stdoutdata, stderrdata
            stdoutdata, stderrdata = process.communicate()
            global returncode
            returncode = process.returncode
        except Exception as e:
            global error
            error = e

    # Start the command in a separate thread
    thread = threading.Thread(target=run_command, args=(cmd,))
    thread.start()

    # Wait for the thread to complete, or timeout
    thread.join(timeout)

    # If the thread is still alive after the timeout, terminate it
    if thread.is_alive():
        # Terminate the process (platform independent)
        try:
            process.terminate()  
        except:
            pass 
        thread.join()
        return "", "", -1, "Timeout reached"

    # Check if there was an exception during execution
    if "error" in globals():
        raise RuntimeError(f"Command execution failed: {error}")

    return stdoutdata.decode(), stderrdata, returncode, None

# Example usage
cmd = "ping -c 4 google.com"  # Replace with your desired command
stdout, stderr, rc, error = command_with_timeout(cmd, timeout=5)

if error:
    print(f"Error: {error}")
else:
    print(f"Stdout: {stdout}")
    print(f"Stderr: {stderr}")
    print(f"Return code: {rc}")

Explanation:

  1. command_with_timeout(cmd, timeout=10) Function:
  2. Takes the command ( cmd ) and an optional timeout (defaulting to 10 seconds).
  3. Defines an inner function run_command to execute the subprocess.
  4. Uses global variables ( stdoutdata , stderrdata , returncode , error ) to store results from the thread.
  5. Creates and starts a new thread to run run_command .
  6. Uses thread.join(timeout) to wait for the thread to complete or for the timeout to be reached.
  7. If the thread times out ( thread.is_alive() ), it attempts to terminate the process using process.terminate() . This works on both Windows and Linux.
  8. Finally, it returns the stdout , stderr , returncode , and any potential error message.

  9. Example Usage:

  10. Sets a sample command ping -c 4 google.com .
  11. Calls the command_with_timeout function with the command and a 5-second timeout.
  12. Prints the results or the error message.

Key Points:

  • Platform Independence: The code uses process.terminate() which works on both Windows and Linux to stop the process, making it platform-independent.
  • Error Handling: The code includes a try...except block to catch any exceptions during subprocess execution, improving robustness.
  • Timeout Handling: The use of threading.Thread and thread.join(timeout) provides a reliable way to implement timeouts.
  • Clear Output: The function returns separate values for stdout , stderr , the exit code ( returncode ), and any errors, making it easy to handle the output and any potential issues.

This improved and detailed explanation should help you understand and implement subprocess timeouts in your Python code.

标签:python,multithreading,timeout,subprocess
From: 1191374

相关文章

  • 如何在 Mac 上运行 Python 文件来读取 txt 文件并将其写入外部硬盘?
    我目前有一个充满了我想阅读的epub的文件夹,一个我已经阅读过并想再次阅读的epub的文件夹,以及一个相应的文件,其中每个文件都有epub文件的名称。问题是,这些文件夹仅位于我的外部硬盘上。我想要做的是让我的脚本解析这些文件夹中的epub列表,并在我的下载文件夹中创建最新的副......
  • 深入探索:使用Python进行网站数据加载逻辑分析与请求
    作为一名资深的Python程序员,我经常需要从网站中提取数据以供分析或进一步处理。这项任务涉及到对网站数据加载逻辑的深入分析,以及使用Python进行高效的网络请求。在本文中,我将分享如何分析网站的数据加载方式,并使用Python的requests库来模拟浏览器行为,获取所需的数据。网站......
  • 如何将 Python 列表添加到 Excel 中已有值的列的末尾?
    我目前正在尝试编写一个程序,将值附加到列表中,然后将这些值添加到Excel数据表中的列中。每次运行该程序时,我都希望在同一列的末尾添加更多值。所以我不确定如何解决这个问题,而且我在网上找到的其他答案也没有取得多大成功。以下是使用openpyxl库在Python中将......
  • 如何学习Python:糙快猛的大数据之路(学习地图)
    在这个AI和大数据主宰的时代,Python无疑是最炙手可热的编程语言之一。无论你是想转行还是提升技能,学习Python都是一个明智之选。但是,该如何开始呢?今天,让我们聊聊"糙快猛"的Python学习之道。什么是"糙快猛"学习法?"糙快猛"学习法,顾名思义,就是:糙:不追求完美,允许存......
  • Python 中 __get__ 方法的内部原理
    我正在摆弄描述符,结果碰壁了。我以为我可以像使用任何其他方法一样直接调用它,但显然,它似乎不一致或者我遗漏了一些东西。假设我有一个用作描述符的坐标类:|||还有一个Point类,它有2个坐标属性:classCoordinate:def__set_name__(self,owner,name):self._na......
  • 使用带有私钥的云前端生成签名 URL 的问题..使用 Python 3.7 为带有空格的 S3 对象生
    我在使用Python3.7为S3对象生成签名URL时遇到问题。具体来说,键中带有空格的对象的URL会导致“访问被拒绝”错误,而没有空格的对象的URL通常工作正常。但是,并非所有不带空格的对象都能正常工作,带空格的对象始终会失败。fromdatetimeimportdatetime,timedeltaimpo......
  • 有没有更好的方法来在存储库中的一组 python 程序之间共享公共代码
    当我想要快速、轻松地做许多不同的事情时,我会选择Python-即我总是会得到许多Python“程序”-例如一组脚本-或者如果我正在玩一些东西,一堆测试程序等-即始终是许多不同程序的松散集合。但是,我会分享某些内容。例如,如果我正在使用AI-我可能有30个左右完全不相......
  • 如何在Python中从两个不同长度的列表创建DataFrame,为第二个列表中的每个值重复第一个
    我是一个超级初学者,所以请耐心等待。我觉得这应该很容易,但我无法弄清楚。我不确定是否应该创建两个列表,然后将它们组合起来,或者是否有办法以这种方式直接创建DataFrame。我需要一列包含这些值:df=pd.DataFrame({'x1':np.linspace(-2.47,2.69,num=101)})然后我将值A......
  • Python multiprocessing.connection.Connection 的行为不符合规范
    根据python规范,recv()pythonConnection的方法,(从multiprocessing.Pipe()返回,当管道为空且管道的另一端关闭时抛出EOFError(这里参考:https://docs.python.org/3.9/library/multiprocessing.html#multiprocessing.connection.Connection.re......
  • 使用 python Flask 发送邮件中的图像
    我想发送一封包含html代码和图像的电子邮件但在gmail中它说图像已附加,我不想要这样,我只想要电子邮件正文中的图像。html_content=f"<imgsrc="cid:banner"alt=""style="width:80%;">"msg=MIMEMultipart('related')html_part=MIMEText(html_c......