2016-01-22 42 views
2

我试图在函数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 

它给了我这样的:

In [6]: l=Link()

In [7]: l.send(1) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in() ----> 1 l.send(1)

TypeError: decorator() takes exactly 1 argument (2 given)

我的问题是,我想的超时值second传递给装饰通过Linkself。我不完全理解这里的整个装饰器机制,也不能弄清楚什么是错的。

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

回答

0

所以我一直在调试我的问题,我找到了工作液:

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),因为它允许设置超时<1秒,与signal.signal()不一样,只接受整数作为定时器。