2012-11-03 13 views
6

Jak zrobić klasyczny zegar w gevent?Something like cron (timer) in gevent

Obecnie używam gevent.spawn_later, ale czy istnieje sposób na użycie core.timer jak powiedz "czy callback na interwał" tak jak robi cron?

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

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

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

Hmm, dlaczego jest Greenlet pętli bez końca, nazywając wywołania zwrotnego i spania, nie wystarczy? –

+0

Używam tego w gunicorn, więc jest to serwer WWW i nie wiem jak to zrobić. Po prostu mam funkcję obsługi, ale prawdopodobnie mógłbym wstawić ten kod wcześniej. Wygląda to dość źle, ponieważ jeśli potrzebuję 10 timerów, potrzebuję 10 wywołań zwrotnych. Czy to będzie działać z gunicornem? – bradojevic

Odpowiedz

7

Na szczycie mojej głowie, można użyć gevent.sleep w pętli:

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) 

Oczywiście, można umieścić ten kod w ładnym API, takich jak core.timer. Ale dam ci całą zabawę :)

+0

dryft czasu z oddzwonienia() – whi

12

To zależy od tego, jak dokładnie chcesz zaplanować swoją pracę. Istnieje kilka mechanizmów:

This blog ma fajny trik na korzystanie gevent.spawn_later stworzyć 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) 

Albo oczywiście można po prostu spać w pętli, która jest prawdopodobnie bardziej czytelne:

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

Jednak oba te elementy będą ulegać dryfowaniu z upływem czasu, szczególnie jeśli wykonanie tej funkcji wymaga czasu w stosunku do interwału. można wyrównać poprzez regulację odstępu uśpienia przez czas potrzebny do wykonywania funkcji:

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)) 

ten będzie nadal dryfować, po prostu nie tak dużo ...

1

Oto wersja, która inicjuje całemu sekundę a następnie koryguje dryf. Może być również stosowany do podziału okresu czasu na kilka odcinków do różnych celów:

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)