Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

understanding asyncio already running forever loop and pending tasks

I'm having problems understanding how to pend a new task to an already running event loop.

This code:

import asyncio
import logging

@asyncio.coroutine
def blocking(cmd):
    while True:
        logging.info("in blocking coroutine")
        yield from asyncio.sleep(0.01)
        print("ping")

def main():
    logging.info("in main funciton")
    loop = asyncio.get_event_loop()
    logging.info("new loop created")
    logging.info("loop running forever")
    loop.run_forever()
    asyncio.async(blocking("ls"))

logging.basicConfig(level = logging.INFO)
main()

Changing run_forever() to run_until_complete(asyncio.async(blocking("ls")) works fine. But I'm really confused - why I can't pend a task on the already running loop?

like image 577
user4549992 Avatar asked May 31 '15 13:05

user4549992


People also ask

How do I stop Asyncio from looping events?

Run an asyncio Event Loop run_until_complete(<some Future object>) – this function runs a given Future object, usually a coroutine defined by the async / await pattern, until it's complete. run_forever() – this function runs the loop forever. stop() – the stop function stops a running loop.

How does the Asyncio event loop work?

Deep inside asyncio, we have an event loop. An event loop of tasks. The event loop's job is to call tasks every time they are ready and coordinate all that effort into one single working machine. The IO part of the event loop is built upon a single crucial function called select .

How many times should Asyncio run () be called?

It should be used as a main entry point for asyncio programs, and should ideally only be called once. New in version 3.7.

How do you stop a running event loop?

Run the event loop until stop() is called. If stop() is called before run_forever() is called, the loop will poll the I/O selector once with a timeout of zero, run all callbacks scheduled in response to I/O events (and those that were already scheduled), and then exit.


1 Answers

The problem is that the call to loop.run_forever() blocks; it starts the event loop, and won't return until you explicitly stop the loop - hence the forever part of run_forever. Your program never explicitly stops the event loop, so your asyncio.async(blocking("ls")) call is never reached.

Using asyncio.async to add a new task to an already running loop is fine, you just need to make sure the function is actually called from inside a coroutine or callback inside the event loop. Here are some examples:

Schedule blocking to run as soon as the event loop starts:

def main():
    logging.info("in main funciton")
    loop = asyncio.get_event_loop()
    logging.info("new loop created")
    logging.info("loop running forever")
    asyncio.async(blocking("ls"))
    loop.run_forever()

Schedule blocking from a callback executed by the event loop:

def start_blocking():
    asyncio.async(blocking("ls"))

def main():
    logging.info("in main funciton")
    loop = asyncio.get_event_loop()
    logging.info("new loop created")
    logging.info("loop running forever")
    loop.call_soon(start_blocking)  # Calls start_blocking once the event loop starts
    loop.run_forever()
like image 102
dano Avatar answered Sep 21 '22 10:09

dano