user3064433
user3064433

Reputation: 83

run async while loop independently

Is it possible to run an async while loop independently of another one?

Instead of the actual code I isolated the issue I am having in the following example code

import asyncio, time

class Time:
    def __init__(self):
        self.start_time = 0

    async def dates(self):
        while True:
            t = time.time()
            if self.start_time == 0:
                self.start_time = t
            yield t
            await asyncio.sleep(1)

    async def printer(self):
        while True:

            print('looping') # always called

            await asyncio.sleep(self.interval)

    async def init(self):
        async for i in self.dates():
            if i == self.start_time: 
                self.interval = 3 
                await self.printer()
            print(i) # Never Called

loop = asyncio.get_event_loop()
t = Time()
loop.run_until_complete(t.init())

Is there a way to have the print function run independently so print(i) gets called each time?

What it should do is print(i) each second and every 3 seconds call self.printer(i)

Essentially self.printer is a separate task that does not need to be called very often, only every x seconds(in this case 3).

In JavaScript the solution is to do something like so setInterval(printer, 3000);

EDIT: Ideally self.printer would also be able to be canceled / stopped if a condition or stopping function is called

Upvotes: 8

Views: 38756

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1123770

You'd want to register your self.printer() coroutine as a separate task; pass it to asyncio.ensure_future() rather than await on it directly:

asyncio.ensure_future(self.printer())

By passing the coroutine to asyncio.ensure_future(), you put it on the list of events that the loop switches between as each awaits on further work to be completed.

With that change, your test code outputs:

1516819094.278697
looping
1516819095.283424
1516819096.283742
looping
1516819097.284152
# ... etc.

Tasks are the asyncio equivalent of threads in a multithreading scenario.

Upvotes: 2

Blender
Blender

Reputation: 298392

The asyncio equivalent of JavaScript's setTimeout would be asyncio.ensure_future:

import asyncio

async def looper():
    for i in range(1_000_000_000):
        print(f'Printing {i}')
        await asyncio.sleep(0.5)

async def main():
    print('Starting')
    future = asyncio.ensure_future(looper())

    print('Waiting for a few seconds')
    await asyncio.sleep(4)

    print('Cancelling')
    future.cancel()

    print('Waiting again for a few seconds')
    await asyncio.sleep(2)

    print('Done')

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())

Upvotes: 10

Related Questions