2011-12-07 47 views
7

我有這個裝飾:蟒蛇:窗戶相當於SIGALRM

def timed_out(timeout): 
    def decorate(f): 
     if not hasattr(signal, "SIGALRM"): 
      return f 

     def handler(signum, frame): 
      raise TimedOutExc() 

     @functools.wraps(f) 
     def new_f(*args, **kwargs): 
      old = signal.signal(signal.SIGALRM, handler) 
      signal.alarm(timeout) 
      try: 
       result = f(*args, **kwargs) 
      finally: 
       signal.signal(signal.SIGALRM, old) 
      signal.alarm(0) 
      return result 

     new_f.func_name = f.func_name 
     return new_f 

    return decorate 

的代碼不僅在Linux上任何東西,不過,因爲在Windows上,沒有SIGALRM。在Windows中使用此代碼的最簡單方法是什麼?

回答

8

這不是很漂亮,但我必須以跨平臺的方式做類似的事情,並且我想出了使用單獨的線程。基於信號的系統無法可靠地在所有平臺上工作。

這個類的使用可以包裝在裝飾器中,或者製作成with上下文處理器。

YMMV。

#!/usr/bin/env python2.7 
import time, threading 

class Ticker(threading.Thread): 
    """A very simple thread that merely blocks for :attr:`interval` and sets a 
    :class:`threading.Event` when the :attr:`interval` has elapsed. It then waits 
    for the caller to unset this event before looping again. 

    Example use:: 

    t = Ticker(1.0) # make a ticker 
    t.start() # start the ticker in a new thread 
    try: 
     while t.evt.wait(): # hang out til the time has elapsed 
     t.evt.clear() # tell the ticker to loop again 
     print time.time(), "FIRING!" 
    except: 
     t.stop() # tell the thread to stop 
     t.join() # wait til the thread actually dies 

    """ 
    # SIGALRM based timing proved to be unreliable on various python installs, 
    # so we use a simple thread that blocks on sleep and sets a threading.Event 
    # when the timer expires, it does this forever. 
    def __init__(self, interval): 
    super(Ticker, self).__init__() 
    self.interval = interval 
    self.evt = threading.Event() 
    self.evt.clear() 
    self.should_run = threading.Event() 
    self.should_run.set() 

    def stop(self): 
    """Stop the this thread. You probably want to call :meth:`join` immediately 
    afterwards 
    """ 
    self.should_run.clear() 

    def consume(self): 
    was_set = self.evt.is_set() 
    if was_set: 
     self.evt.clear() 
    return was_set 

    def run(self): 
    """The internal main method of this thread. Block for :attr:`interval` 
    seconds before setting :attr:`Ticker.evt` 

    .. warning:: 
     Do not call this directly! Instead call :meth:`start`. 
    """ 
    while self.should_run.is_set(): 
     time.sleep(self.interval) 
     self.evt.set() 
0

我覺得這個timeout-decorator代碼也非常方便。 (我最初發現它在這個問題的答案:How to limit execution time of a function call in Python

爲了使它在Windows上工作,我使用與Cygwin一起安裝的Python。

我運行setup-x86_64.exe,然後從Python文件夾中選擇python3包。 (或者,如果你喜歡的Python 2,python包)。

要重命名python3到python2,我從Cygwin的命令提示符下定義別名

alias python=python3 

。由於我不經常使用這個功能,我可能不會把它放到.bashrc或其他東西中。

相關問題: Python signal don't work even on Cygwin?

+0

可能有人指出,什麼是錯的這個答案?我自己沒有看到任何問題。 (我是作者) –