2012-11-03 40 views
6

如何在gevent中制作古典计时器?somethig like cron(timer)in gevent

我目前正在使用gevent.spawn_later,但是有没有一种方法可以像cron一样使用core.timer,比如说“在间隔时间内执行回调”?

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

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

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

嗯,为什么一个greenlet循环不休,调用回调和睡眠,还不够吗? –

+0

我在gunicorn中使用它,所以它是web服务器,我不知道该怎么做。我只有处理函数,但我可能会在那之前插入该代码。这看起来有点不好,因为如果我需要10个定时器,我需要10个回调。这甚至会和gunicorn一起工作吗? – bradojevic

回答

7

在我的头顶,你可以在一个循环中使用gevent.sleep:

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) 

当然,你可以把这个代码在一个不错的API,如core.timer。但我会让所有的乐趣:)

+0

回调时间漂移() – whi

12

这取决于你想如何准确地安排你的工作。有几个机制:

This blog有使用gevent.spawn_later创建一个定时器一个绝招:

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) 

或课程,你可以在一个循环这可能是更具可读性只是睡觉:

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

但是,这两者都会随着时间而漂移,特别是如果您的功能相对于间隔需要时间才能完成。您可以通过该功能将执行时间调整睡眠间隔补偿:

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

这仍然会漂移,只是没有那么多...

1

下面是初始化整个第二版本并随后纠正任何漂移。它也可以用来划分一个时间段成用于不同目的的几个部分:

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)