python 设置运行超时的方式(subprocess、main)

场景是需要函数或子进程在指定时间内完成,但不是最简单的time.sleep()的方式(这会造成每次都最大等待)

运行环境:

python 3.6+

linux

设置子进程运行超时时间

import subprocess

def test(_timeout=2):
    # 这里ls -lrt可以换成自己的任意模块,这里stdout也可以是文件流
    with subprocess.Popen("ls -lrt", shell=True, stdout=subprocess.PIPE) as p:
        try:
            bs=p.communicate(timeout=_timeout)[0]
            if bs:
                bs_split = eval(bs)
                res = ''
                for line in bs_split:
                    res += line.decode()
                print(res)
        except Exception as e:
            # 未在指定时间内完成,此处会有异常。主进程在根据情况做处理
            print(e)
            p.terminate()


test(1)

这里是开启了pipe管道模式,让主进程与子进程进行交互。pipe管道有大小限制(默认64k),如果我们先使用Popen.poll()或者Popen.wait()后在readline或者readlines,在子进程输出数据较多的情况下很容易造成死锁,原因是子进程写满管道后需要等待管道中有空余空间才能再次写入。Popen.communicate 就能完成如此操作。这里推荐大家用subprocess ,因为类似os.popen等都是调用subprocess。子进程会有巨量输出的情况下,不能使用这种模式。

os.popen

def popen(cmd, mode="r", buffering=-1):
    if not isinstance(cmd, str):
        raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
    if mode not in ("r", "w"):
        raise ValueError("invalid mode %r" % mode)
    if buffering == 0 or buffering is None:
        raise ValueError("popen() does not support unbuffered streams")
    import subprocess, io
    if mode == "r":
        proc = subprocess.Popen(cmd,
                                shell=True,
                                stdout=subprocess.PIPE,
                                bufsize=buffering)
        return _wrap_close(io.TextIOWrapper(proc.stdout), proc)
    else:
        proc = subprocess.Popen(cmd,
                                shell=True,
                                stdin=subprocess.PIPE,
                                bufsize=buffering)
        return _wrap_close(io.TextIOWrapper(proc.stdin), proc)

主线程中对函数设置超时时间

import signal
import time
from functools import wraps
import signal

class TimeoutException(Exception):
    pass


def timeout_func(timeout=1, default_return=None):
    def decorateFunction(function):
        @wraps(function)
        def wrapper(*args, **kv):
            def handler(signum, frame):
                raise TimeoutException()

            # 设置回调handler
            signal.signal(signal.SIGALRM, handler)
            signal.alarm(timeout)
            try:
                result = function(*args, **kv)
            except TimeoutException as e:
                print(e)
                result = default_return
            finally:
                signal.alarm(0)
                signal.signal(signal.SIGALRM, signal.SIG_DFL)

            return result
        return wrapper
    return decorateFunction

# 装饰器模式
@timeout_func(timeout=2, default_return=0)
def test_timeout(sec, a, b):
    time.sleep(sec)
    return a + b


print(test_timeout(1.99, 2, 3))


# 输出5

注意 : signal.alarm只有linux下才有,window下没有。signal.alarm设置了告警时间以及回调函数后,只会在主线程中进行中断回调。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设置 subprocess.Popen 的运行超时,可以结合使用 timeout 命令和 subprocess.Popen 的 poll 方法。首先,可以使用 timeout 命令来为执行的命令设置超时时间。比如,可以使用以下代码来设置超时时间为5秒: timeout 5s your_command 然后,可以使用 subprocess.Popen 来执行这个 timeout 命令。可以使用类似以下的代码: import subprocess cmd = ['timeout', '5s', 'your_command'] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() 接下来,可以使用 subprocess.Popen 的 poll 方法来检查进程是否已经结束。如果 poll 方法返回 None,则表示进程还在运行。如果 poll 方法返回一个整数,则表示进程已经结束,并可以根据返回值判断进程的状态。比如,返回值为 0 表示进程正常结束,而其他返回值则表示进程异常结束。 status = p.poll() if status is None: print("Process is still running") else: print("Process has ended with status", status) 综上所述,结合使用 timeout 命令和 subprocess.Popen 的 poll 方法,可以实现对 subprocess.Popen 的运行超时设置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [python subprocess.Popen系列问题](https://blog.csdn.net/weixin_36102930/article/details/113639509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值