【问题标题】:Timeout a function inside a class with a decorator使用装饰器使类中的函数超时
【发布时间】:2016-04-29 01:47:35
【问题描述】:

我正在尝试对函数 send 设置超时。

我在这些帖子中发现了一些元素:

第一个似乎适用于每个函数,而不是一个精确的函数,这就是我选择第二个这样的装饰器实现的原因。

我试着把它混合起来,我有这个:

from functools import wraps
import os
import signal

class TimeoutError(Exception):
    pass

def timeout_func(error_message="Timeout in send pipe!"):
    def decorator(func):
        def _handle_timeout(signum, frame):
            if args[0].action=="warn":
                print "WARNING : ",error_message
            elif args[0].action=="kill":
                raise TimeoutError(error_message)

        def wrapper(*args, **kwargs):
            print args
            signal.signal(signal.SIGALRM, _handle_timeout,args[0].action)
            signal.alarm(args[0].seconds)
            print str(args)
            try:
                result = func(*args, **kwargs)
            finally:
                signal.alarm(0)
            return result
        return wraps(func)(wrapper)
    return decorator

class Link(object):
    def __init__(self,timeout=1,action="warn"):
        self.timeout=timeout
        self.action=action

    @timeout_func
    def send(self,value):
        print "working : ", value

它给了我这个:

在[6]中:l=Link()

在 [7] 中:l.send(1) -------------------------------------------------- ------------------------- TypeError Traceback(最近一次调用 最后)在() ----> 1 l.send(1)

TypeError: decorator() 只接受 1 个参数(给定 2 个)

我的问题是我想通过Linkself 将超时值second 传递给装饰器。这里我对整个装饰器机制不是很了解,也不知道哪里出了问题。

谁能解释一下这个装饰器是如何工作的,我应该修改什么来修复它?或者,如果您想到一个更简单/更明确的解决方案来实现它?

【问题讨论】:

    标签: python python-2.7 timeout decorator


    【解决方案1】:

    所以我一直在调试我的问题,我找到了一个可行的解决方案:

    from functools import wraps
    import signal
    
    class TimeoutError(Exception):
        pass
    
    def timeout_func(f):
        def _handle_timeout(signum, frame):
            raise TimeoutError("timeout error")
    
        def wrapper(*args):
            signal.signal(signal.SIGALRM, _handle_timeout)
            signal.setitimer(signal.ITIMER_REAL,args[0].timeout) #args[0] is self of Link class here
            try:
                result = f(*args,**kwargs)
            finally:
                signal.alarm(0)
            return result
        return wrapper
    
    
    class Link(object):
        def __init__(self,timeout=0.1,action="warn"):
            self.timeout=timeout
            self.action=action
    
        def send(self,value): # I use this func to handle the exceptions
            try:
                self.send_timeout(value) # call the timeout function
            except TimeoutError as e: # handle Timeout exception
                if self.action=="warn":
                    print "WARNING : Timeout error in pipe send!"
                elif self.action=="kill":
                    print "Killing Link : ", e
                    raise
            except (Exception,KeyboardInterrupt) as e:
                print "Exception in link : ", e
                raise
    
        @timeout_func # apply timeout decorator to this function
        def send_timeout(self,value):
            # DO STUFF HERE 
    

    叫它:

    l=Link()
    l.send("any value")
    

    我使用 signal.setitimer(signal.ITIMER_REAL,args[0].timeout),因为它允许设置超时 signal.signal() 不是这种情况,它只接受整数作为计时器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-25
      • 2019-07-23
      • 2018-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-09
      • 2020-06-08
      相关资源
      最近更新 更多