Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async iterator ticking at a regular interval

I am implementing an asynchronous iterator to be used with async for which should return a new value at a (mostly) regular interval.

We can illustrate such iterator with a simple clock that will increment a counter every ~n seconds:

import asyncio

class Clock(object):
    def __init__(self, interval=1):
        self.counter = 0
        self.interval = interval
        self.tick = asyncio.Event()
        asyncio.ensure_future(self.tick_tock())

    async def tick_tock(self):
        while True:
            self.tick.clear()
            await asyncio.sleep(self.interval)
            self.counter = self.__next__()
            self.tick.set()

    def __next__(self):
        self.counter += 1
        return self.counter

    def __aiter__(self):
        return self

    async def __anext__(self):
        await self.tick.wait()
        return self.counter

Is there a better or cleaner approach than using asyncio.Event? More than one coroutine will async for on this iterator.

like image 418
DurandA Avatar asked Oct 29 '22 00:10

DurandA


1 Answers

In my opinion, your approach is fine. Note that since python 3.6, you can also use asynchronous generators:

async def clock(start=0, step=1, interval=1.):
    for i in count(start, step):
        yield i
        await asyncio.sleep(interval)

However, you won't be able to share them between multiple coroutines. You would have to run the clock in a task and make the data available through an asynchronous iteration interface, which is essentially what you did in your code. Here's a possible implementation.

like image 55
Vincent Avatar answered Nov 11 '22 15:11

Vincent