2012-11-03 7 views
6

Come posso creare un timer classico in gevent?qualcosa come cron (timer) in gevent

Attualmente sto usando gevent.spawn_later ma c'è un modo per usare core.timer come dire "richiamare su intervallo" proprio come fa cron?

def callback(): 
    # do something 
    print '!' 

timer = core.timer(10, callback) 
timer.start() 

outpout: 
0s 
10s ! 
20s ! 
30s ! 
+1

Hmm, perché è un greenlet un loop senza fine, chiamando un callback e dormire, non basta? –

+0

Lo uso in gunicorn, quindi è un server web e non so come farlo. Ho solo la funzione di gestore, ma probabilmente potrei inserire quel codice prima di quello. Sembra un pò brutto farlo perché se ho bisogno di 10 timer, ho bisogno di 10 callback. Funzionerà anche con Gunicorn? – bradojevic

risposta

7

Sulla parte superiore della mia testa, è possibile utilizzare gevent.sleep in un ciclo:

import gevent 
import gevent.monkey 

gevent.monkey.patch_all() 

INTERVAL = 10 

def callback(): 
    # do something 
    print "!" 

def loop(): 
    while True: 
     gevent.sleep(INTERVAL) 
     callback() 

gevent.Greenlet.spawn(loop) 

Naturalmente, si può inserire questo codice in una bella API, come core.timer. Ma ti lascio tutto il divertimento per te :)

+0

deriva dal richiamo() – whi

12

Dipende da quanto accuratamente si desidera pianificare il proprio lavoro. Ci sono un paio di meccanismi:

This blog ha un trucco per l'utilizzo di gevent.spawn_later per creare un timer:

def schedule(delay, func, *args, **kw_args): 
    gevent.spawn_later(0, func, *args, **kw_args) 
    gevent.spawn_later(delay, schedule, delay, func, *args, **kw_args) 

O, naturalmente, semplicemente si può dormire in un ciclo che è probabilmente più leggibile:

def run_regularly(self, function, interval, *args, **kwargs): 
    while True: 
     gevent.sleep(interval) 
     function(*args, **kwargs) 

Tuttavia entrambi si spostano nel tempo, in particolare se la tua funzione richiede del tempo per il completamento rispetto all'intervallo. È possibile compensare regolando l'intervallo di sonno dal momento in cui la funzione di necessario per eseguire:

def run_regularly(self, function, interval, *args, **kwargs): 
    while True: 
     before = time.time() 
     function(*args, **kwargs) 

     duration = time.time() - before 
     if duration < interval: 
      gevent.sleep(interval-duration) 
     else: 
      warning("function %s duration exceeded %f interval (took %f)" % (
       function.__name__, interval, duration)) 

Questo sarà ancora alla deriva, ma non abbastanza tanto ...

1

Ecco una versione che inizializza per tutta la seconda e successivamente corregge qualsiasi deriva. Può anche essere utilizzata per dividere un periodo di tempo in varie sezioni per diversi scopi:

import time 
import gevent 

def print_time(sleep_time, tag): 
    print time.time(), tag 
    time.sleep(sleep_time) 


def run_regularly(function, intervals, sleep_time=0.1, round_length=1): 
    _, init = divmod(time.time(), 1) 
    gevent.sleep(1 - init) 
    while True: 
     before = time.time() 
     _, offset = divmod(before, round_length) 
     for div in intervals: 
      function(sleep_time, div) 
      after = time.time() - before 
      if after < (div * round_length): 
       gevent.sleep((div * round_length) - after - (offset/len(intervals))) 

gevent.spawn(run_regularly, print_time, [0.2, 0.8, 1.0]) 

while 1: 
    gevent.sleep(0.1)