栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

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

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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设置了告警时间以及回调函数后,只会在主线程中进行中断回调。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/925825.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号