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

Ian Kelly ian.g.kelly at gmail.com
Mon Apr 2 09:36:11 EDT 2018


On Mon, Apr 2, 2018 at 5:32 AM,  <jfong at ms4.hinet.net> wrote:
> I am new to the asyncio subject, just trying to figure out how to use it. Below is the script I use for testing:
> ---------------------------------
> # asyncio_cancel_task2.py
>
> import asyncio
>
> @asyncio.coroutine
> def task_func():
>     print('in task_func, sleeping')
>     try:
>         yield from asyncio.sleep(1)
>     except asyncio.CancelledError:
>         print('task_func was canceled')
>         raise
>     print('return result')
>     return 'the result'
>
> def task_canceller(task):
>     task.cancel()
>     print('canceled the task')
>
> @asyncio.coroutine
> def main(loop):
>     print('first, scheduling a task')
>     task = loop.create_task(task_func())
>     print('second, scheduling its cancellation')
>     loop.call_later(0.5, task_canceller, task)
>     try:
>         print('waiting task to complete')
>         yield from task
>     except asyncio.CancelledError:
>         print('main() also sees task as canceled')
>
>
> event_loop = asyncio.get_event_loop()
> try:
>     event_loop.run_until_complete(main(event_loop))
> finally:
>     print('wait 3 seconds before closing event_loop')
>     asyncio.sleep(3)

This won't actually wait 3 seconds. It just instantiates a sleep
coroutine and then discards it. Inside the event loop you would need
to await or yield from it. Outside the event loop, in order to sleep
you have to block the thread, e.g. using time.sleep. That said, there
is no reason to wait before closing the event loop.

>     print('event_loop was closed')
>     event_loop.close()
> -----------------------------------
>
> It schedules two tasks, the task_func and the task_canceller, in main. Before the task_func completed, the task_canceller was fired to cancel it. Hence its output below seems reasonable.
>
> D:\Works\Python>py
> Python 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 19:28:18) [MSC v.1600 32 bit (Intel)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
>>>> import asyncio_cancel_task2
> first, scheduling a task
> second, scheduling its cancellation
> waiting task to complete
> in task_func, sleeping
> canceled the task
> task_func was canceled
> main() also sees task as canceled
> wait 3 seconds before closing event_loop
> event_loop was closed
>>>>
>
> Then, I changed the call_later delay from 0.5 to 1.5, expect it to be called after the task_func completed and before the event loop closed. The output seems not quite right. Why the task_canceller hasn't been called?
>
>>>> import asyncio_cancel_task2
> first, scheduling a task
> second, scheduling its cancellation
> waiting task to complete
> in task_func, sleeping
> return result
> wait 3 seconds before closing event_loop
> event_loop was closed
>>>>

Because, as your thread title suggests, after run_until_complete
returns, the event loop is not running. How could it? It needs a
thread to run on, but it doesn't create one, so whenever it returns
from running it is relinquishing the thread and can't do anything
unless it gets it back, since that thread is now running outer code.
If you want to, you can restart the event loop by calling one of the
run methods again; everything that was previously scheduled and
everything that was scheduled after it stopped will remain scheduled.

So, you can't have the event loop running in the background while also
doing things within the code that started the loop in the same thread.
If you really want this you can create a second thread to run the
event loop on. However it is usually better to do that sort of thing
within a coroutine running in the event loop, since single-threaded
concurrency is the whole point of asyncio. The code that started the
event loop will then only be used for cleanup after it terminates.


More information about the Python-list mailing list