Periodic execution with asyncio

Phil Connell pconnell at gmail.com
Mon Nov 25 11:52:54 CET 2013


On Sat, Nov 23, 2013 at 09:30:29PM +0100, Tobias M. wrote:
> Now putting this into a PeriodicTask class that provides a similar interface
> like our callback version, I get:
> 
> 
> import asyncio
> 
> class PeriodicTask2(object):
> 
>      def __init__(self, func, interval):
>          self.func = func
>          self.interval = interval
>          self._loop = asyncio.get_event_loop()
> 
>      def start(self):
>          self.loop.run_until_complete(asyncio.Task(self._run()))
> 
>     @asyncio.coroutine
>      def _run(self):
>          while True:
>                 yield from asyncio.sleep(self.interval)
>                 self.func()
> 
> 
> I don't know if I misunderstood anything, but as a user of this class I am
> not able to run two task simultaneously because start() will block. In the
> callback version I could instanciate two PeriodicTasks and run them both at
> the same time (after a call to loop.run_forever()), which is actually what I
> wanted to achieve with this class.

You need to separate out creating tasks from running the event loop.

Specifically, you should run the event loop in exactly one place, probably at
the top level of your script.


A toy example:

import asyncio

@asyncio.coroutine
def adder(*args, delay):
    yield from asyncio.sleep(delay)
    print(sum(args))

def main():
    asyncio.Task(adder(1, 2, 3, delay=5))
    asyncio.Task(adder(10, 20, delay=3))

    loop = asyncio.get_event_loop()
    loop.run_forever()

if __name__ == "__main__":
    main()


$ ./python test.py
30
6


Note that run_forever() will block indefinitely (as the name suggests :). This
is generally what you'll want for a long-running server.

If you want do something more like:
    - Spawn some tasks
    - Run the event loop until they're done
    - Exit

then you'll need to use loop.run_until_complete(asyncio.gather(*tasks))
instead.


HTH,
Phil




More information about the Python-list mailing list