8

如何在 gevent 中制作经典计时器?

我目前正在使用 gevent.spawn_later 但有没有办法像 cron 一样使用 core.timer 说“在间隔上进行回调”?

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

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

outpout:
0s
10s  !
20s  !
30s  !
4

3 回答 3

17

这取决于您希望安排工作的准确程度。有两种机制:

这个博客有一个巧妙的技巧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))

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

于 2014-10-24T13:36:20.580 回答
8

在我的脑海中,您可以循环使用 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。但我会让你所有的乐趣:)

于 2012-12-13T22:05:25.567 回答
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)
于 2015-09-23T12:51:03.327 回答