nmurthy
nmurthy

Reputation: 1587

Is there anything in Python 2.7 akin to Go's `time.Tick` or Netty's `HashedWheelTimer`?

I write a lot of code that relies on precise periodic method calls. I've been using Python's futures library to submit calls onto the runtime's thread pool and sleeping between calls in a loop:

executor = ThreadPoolExecutor(max_workers=cpu_count())

def remote_call():
    # make a synchronous bunch of HTTP requests

def loop():
    while True:
        # do work here
        executor.submit(remote_call)
        time.sleep(60*5)

However, I've noticed that this implementation introduces some drift after a long duration of running (e.g. I've run this code for about 10 hours and noticed about 7 seconds of drift). For my work I need this to run on the exact second, and millisecond would be even better. Some folks have pointed me to asyncio ("Fire and forget" python async/await), but I have not been able to get this working in Python 2.7.

I'm not looking for a hack. What I really want is something akin to Go's time.Tick or Netty's HashedWheelTimer.

Upvotes: 3

Views: 432

Answers (1)

user2357112
user2357112

Reputation: 281958

Nothing like that comes with Python. You'd need to manually adjust your sleep times to account for time spent working.

You could fold that into an iterator, much like the channel of Go's time.Tick:

import itertools
import time
import timeit

def tick(interval, initial_wait=False):
    # time.perf_counter would probably be more appropriate on Python 3
    start = timeit.default_timer()

    if not initial_wait:
        # yield immediately instead of sleeping
        yield

    for i in itertools.count(1):
        time.sleep(start + i*interval - timeit.default_timer())
        yield

for _ in tick(300):
    # Will execute every 5 minutes, accounting for time spent in the loop body.
    do_stuff()

Note that the above ticker starts ticking when you start iterating, rather than when you call tick, which matters if you try to start a ticker and save it for later. Also, it doesn't send the time, and it won't drop ticks if the receiver is slow. You can adjust all that on your own if you want.

Upvotes: 5

Related Questions