python限制函数运行时间,实现函数执行超时返回

两种思路,一个是用signal,一个是多线程

先来说第一种思路,首先需要明确,signal只能用在主线程里,所以如果是非主程序中调用的函数,此方案不合适

import signal
import time
 
def set_timeout(num, callback):
    def wrap(func):
        def handle(signum, frame):  # 收到信号 SIGALRM 后的回调函数,第一个参数是信号的数字,第二个参数是the interrupted stack frame.
            raise RuntimeError
 
        def to_do(*args, **kwargs):
            try:
                signal.signal(signal.SIGALRM, handle)  # 设置信号和回调函数
                signal.alarm(num)  # 设置 num 秒的闹钟
                print('start alarm signal.')
                r = func(*args, **kwargs)
                print('close alarm signal.')
                signal.alarm(0)  # 关闭闹钟
                return r
            except RuntimeError as e:
                callback()
 
        return to_do
 
    return wrap
 
def after_timeout():  # 超时后的处理函数
    print("Time out!")
 
@set_timeout(2, after_timeout)  # 限时 2 秒超时
def connect():  # 要执行的函数
    time.sleep(3)  # 函数执行时间,写大于2的值,可测试超时
    print('Finished without timeout.')
 
if __name__ == '__main__':
    connect()

第二种,建立子线程监控函数执行状态,缺点是需要循环监控返回值,资源消耗较大

import time
import threading

class MyThread(threading.Thread):
    def __init__(self, target, args=()):
        """
            因为threading类没有返回值,因此在此处重新定义MyThread类,使线程拥有返回值
        """
        super(MyThread, self).__init__()
        self.func = target
        self.args = args

    def run(self):
        # 接受返回值
        self.result = self.func(*self.args)

    def get_result(self):
        # 线程不结束,返回值为None
        try:
            return self.result
        except Exception:
            return None

def limit_decor(timeout, granularity):
    """
        timeout 最大允许执行时长, 单位:秒
        granularity 轮询间隔,间隔越短结果越精确同时cpu负载越高
        return 未超时返回被装饰函数返回值,超时则返回 None
    """
    def functions(func):
        def run(*args):
            thre_func = MyThread(target=func, args=args)
            thre_func.setDaemon(True)
            thre_func.start()
            sleep_num = int(timeout//granularity)
            for i in range(0, sleep_num):
                infor = thre_func.get_result()
                if infor:
                    return infor
                else:
                    time.sleep(granularity)
            return None
        return run
    return functions
    
@limit_decor(2, 0.02)
def test_func():
    time.sleep(3) 
    return 1

print(test_func())
其他解决方案也总结一下
  • 使用eventlet ,测试未成功,可以自行测试
  • 使用timeout-decorator,该工具就是封装了signal和多进程轮询的方法来达到终止程序的目的,缺点是相对于多线程资源消耗太大

参考链接
https://blog.csdn.net/dcrmg/article/details/82850457?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

https://segmentfault.com/q/1010000006090519?_ea=1016686

https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值