2011-12-07 13 views
7

ho questo decoratore:pitone: finestre equivalente di 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 

Il codice solo fa qualsiasi cosa su Linux, anche se, come su Windows, non c'è SIGALRM. Quale sarebbe il modo più semplice per far funzionare questo codice anche in Windows?

risposta

8

Non è molto bello, ma ho dovuto fare qualcosa di simile in un modo multipiattaforma, e mi è venuto in mente usando un thread separato. I sistemi basati sul segnale non hanno funzionato su tutte le piattaforme in modo affidabile.

L'utilizzo di questa classe può essere incluso in un decoratore o trasformato in un gestore di contesto 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

Trovo molto utile questo codice timeout-decoratore. (Originariamente l'ho trovato in questa domanda risposta: How to limit execution time of a function call in Python)

Per farlo funzionare su Windows, utilizzo Python installato con Cygwin.

Eseguo setup-x86_64.exe, quindi selezionare il pacchetto python3 dalla cartella Python. (O, se si preferisce Python 2, il pacchetto python.)

Per rinominare python3 a python2, definisco l'alias

alias python=python3 

dal prompt dei comandi Cygwin. Dal momento che non uso questa funzionalità molto spesso, probabilmente non lo inserirò in un file .bashrc o altro.

questione connessa: Python signal don't work even on Cygwin?

+0

Qualcuno potrebbe sottolineare quello che è sbagliato con questa risposta? Non vedo nessun problema con me stesso. (Sono l'autore) –