In asyncio, does the event_loop still running after run_until_complete returned?

Ian Kelly ian.g.kelly at gmail.com
Tue Apr 3 01:37:51 EDT 2018


On Mon, Apr 2, 2018 at 9:01 PM,  <jfong at ms4.hinet.net> wrote:
> I also do a quick check, with call_later delay keeps at 1.5, to see what the event loop status is after run_until_complete returns. Strangely, both is_closed and is_running return a False.
>
>     try:
>         event_loop.run_until_complete(main(event_loop))
>     finally:
>         print(event_loop.is_closed())  # print(event_loop.is_running())
>         ....
>
> It's not closed(OK, the event_loop.close hasn't be executed yet) and neither it's running(quote your words, "it is relinquishing the thread and can't do anything")!

Correct.

> Event loop, coroutine, task, yield from, ...etc, all these words' interaction makes asyncio has more mystery than I think:-(

If it helps to demystify things, here is a simplified version of what
run_until_complete actually does:

    def run_until_complete(self, future):
        """Run until the Future is done.

        If the argument is a coroutine, it is wrapped in a Task.

        Return the Future's result, or raise its exception.
        """
       future = tasks.ensure_future(future, loop=self)
        future.add_done_callback(self.stop)
        self.run_forever()
        future.remove_done_callback(self.stop)
        return future.result()

    def run_forever(self):
        """Run until stop() is called."""
       try:
            events._set_running_loop(self)
            while True:
                self._run_once()
                if self._stopping:
                    break
        finally:
            self._stopping = False
            events._set_running_loop(None)

    def stop(self):
        """Stop running the event loop.

        Every callback already scheduled will still run.  This simply informs
        run_forever to stop looping after a complete iteration.
        """
        self._stopping = True

run_until_complete sets up a callback on its argument that will stop
the loop, and then it calls run_forever. The key thing to note is that
inside run_forever, there is an actual while loop. This is the heart
of the "event loop". On every iteration of the loop, it checks what
callbacks need to be called and what coroutines need to be resumed.
Then it checks whether it should stop, by breaking out of the loop.

In order for run_until_complete to return, run_forever must first
return. In order for run_forever to return, the loop in its body must
be broken out of. Therefore, when run_forever or run_until_complete
return, the loop can no longer be running. This is all that I mean
when I say it relinquishes the thread: the function that contains the
loop had to return, and therefore the loop is stopped.


More information about the Python-list mailing list