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

jfong at ms4.hinet.net jfong at ms4.hinet.net
Mon Apr 2 23:01:12 EDT 2018


Ian於 2018年4月2日星期一 UTC+8下午9時37分08秒寫道:
> 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.
> 
Thank you for reminding my mistake. I shouldn't use asyncio.sleep there.

> >     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.
> 
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")!

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

> 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