2010-02-08 16 views
50

Voglio eseguire una funzione ogni 60 secondi su Python ma non voglio essere bloccato nel frattempo.Come eseguire una funzione in modo asincrono ogni 60 secondi in Python?

Come posso farlo in modo asincrono?

import threading 
import time 

def f(): 
    print("hello world") 
    threading.Timer(3, f).start() 

if __name__ == '__main__': 
    f()  
    time.sleep(20) 

Con questo codice, la funzione f viene eseguita ogni 3 secondi entro i 20 secondi di tempo. Alla fine dà un errore e penso che sia perché il threading.timer non è stato cancellato.

Come posso annullarlo?

Grazie in anticipo!

+0

Il programma termina dopo aver spawnato il primo timer. –

+0

Per cancellare il Timer è necessario mantenere un riferimento ad esso da qualche parte, e chiamare il suo metodo 'cancel'. –

+0

Si noti che tutte le soluzioni pubblicate fino ad ora soffrono di un (piccolo) accumulo cumulativo di errori. Cioè, piuttosto che calcolare la durata del sonno successivo in base a un orario di partenza fisso, semplicemente dormono per "altri 60 secondi". Questo non dormirà mai per meno di 60 anni e di solito dormirà per poco più di 60 secondi. Questo non è sempre un problema, ma se vuoi dormire esattamente 1440 volte al giorno, assicurati di compensare questo errore. –

risposta

87

Si potrebbe provare la classe Threading.Timer: http://docs.python.org/library/threading.html#timer-objects.

import threading 

def f(f_stop): 
    # do something here ... 
    if not f_stop.is_set(): 
     # call f() again in 60 seconds 
     threading.Timer(60, f, [f_stop]).start() 

f_stop = threading.Event() 
# start calling f now and every 60 sec thereafter 
f(f_stop) 

# stop the thread when needed 
#f_stop.set() 
+0

con quel codice si esegue solo una volta, manca qualcosa per eseguire più volte? –

+3

Devi '.start()' il Timer, l'ho modificato. –

+0

Oops, grazie per aver aggiunto .start() ... avrei dovuto copiarlo/incollarlo dal mio interprete :). Ora dovrebbe davvero essere chiamato ogni 60 secondi anziché solo una volta. –

0

Perché non si crea un thread dedicato, in cui si mette un semplice ciclo di sonno:

#!/usr/bin/env python 
import time 
while True: 
    # Your code here 
    time.sleep(60) 
+7

Questo non è Python. –

+1

No, ma questa è l'idea. Quando ho risposto, non c'era il codice, quindi era solo un'idea. – Aif

+0

@MikeGraham Potresti spiegare perché non è Python? – Dunatotatos

2

Il modo più semplice è quello di creare un thread in background che viene eseguito qualcosa ogni 60 secondi. Un'implementazione banale è:

class BackgroundTimer(Thread): 
    def run(self): 
     while 1: 
     Time.sleep(60) 
     # do something 


# ... SNIP ... 
# Inside your main thread 
# ... SNIP ... 

timer = BackgroundTimer() 
timer.start() 

Ovviamente, questo se il "fare qualcosa" richiede molto tempo, avrete bisogno di ospitare per esso nella sua dichiarazione sonno. Ma questo serve come buona approssimazione.

+0

Spero ti renderai conto che il metodo vuoto '__init__' è superfluo :) –

+0

Ovviamente ... risolto :-) Grazie. – 0xfe

+0

Il modo per essere indipendenti dal tempo di esecuzione è utilizzare un orologio in tempo reale (ad esempio, 'time.time()' o 'datetime.now() '), controlla l'ora all'inizio dell'esecuzione dell'attività, aggiungi 60 secondi per ottenere il tempo per l'accensione successiva, quindi controlla di nuovo alla fine e sottrai quella dal tempo di attivazione successivo per ottenere il tempo di sospensione. –

2

Dipende da ciò che si vuole effettivamente fare nel frattempo. I thread sono il modo più generale e meno preferito di farlo; si deve essere consapevoli dei problemi con filettatura quando lo si utilizza: non tutti (non-Python) codice consente l'accesso da più thread contemporaneamente, la comunicazione tra i thread dovrebbe essere fatto utilizzando strutture di dati thread-safe come Queue.Queue, non sarà in grado di interrompere il thread dall'esterno e terminare il programma mentre il thread è ancora in esecuzione può portare a un interprete appeso oa traceback spurie.

Spesso c'è un modo più semplice. Se stai facendo questo in un programma con interfaccia grafica, usa il timer della biblioteca della GUI o la funzionalità dell'evento. Tutte le interfacce grafiche hanno questo. Allo stesso modo, se si sta utilizzando un altro sistema di eventi, come la torta o di un altro modello di server-processo, si dovrebbe essere in grado di collegare in loop evento principale per indurlo a chiamare la funzione regolarmente. Gli approcci non-threading causano il blocco del programma mentre la funzione è in sospeso, ma non tra i functioncall.

+0

Il trap con questo timer su una GUI è che la GUI è bloccata mentre si gestisce il timeout. Se l'attività è breve, nessun problema. In caso contrario, il tuo programma sembra bloccarsi ogni minuto. –

2

Ho cercato su google e trovato Python circuits Framework, che consente di attendere
per un evento particolare.

Il .callEvent(self, event, *channels) metodo di circuiti contiene un incendio e di sospensione fino a risposta funzionalità, la documentazione dice:

Fuoco la data dell'evento per i canali specificati e sospendere l'esecuzione fino a quando non è stato spedito. Questo metodo può essere attivato solo in argomento di un yield sul livello esecutivo cima di un gestore (ad esempio "yield self.callEvent(event)"). Si crea in modo efficace e restituisce un generatore che verrà richiamato dal ciclo principale fino a quando l'evento è stato inviato (vedi: func: circuits.core.handlers.handler).

Spero che troviate utile come faccio io :)
./regards

+0

Anche se leggermente fuori tema. Questo è un collegamento eccellente. – Glycerine

1

Se si vuole invocare il metodo "l'orologio" (ad esempio ogni ora allo scoccare), è possibile integrare la seguente idea con qualsiasi meccanismo di filettatura che si sceglie:

import time 

def wait(n): 
    '''Wait until the next increment of n seconds''' 
    x = time.time() 
    time.sleep(n-(x%n)) 
    print time.asctime() 
1

penso che il modo giusto per eseguire ripetutamente un thread è il prossimo:

import threading 
import time 

def f(): 
    print("hello world") # your code here 
    myThread.run() 

if __name__ == '__main__': 
    myThread = threading.Timer(3, f) # timer is set to 3 seconds 
    myThread.start() 
    time.sleep(10) # it can be loop or other time consuming code here 
    if myThread.is_alive(): 
     myThread.cancel() 

Con questo codice, la funzione f viene eseguita ogni 3 secondi entro i 10 secondi time.sleep (10). Alla fine l'esecuzione del thread è annullata.

Problemi correlati