asyncio - how to stop loop?

Frank Millman frank at chagford.com
Thu Jun 12 04:00:44 EDT 2014


"Ian Kelly" <ian.g.kelly at gmail.com> wrote in message 
news:CALwzidnv07Wba9WJ=Nuc0_v4mvudYAXWh6BgjvW0o1hF3ooWkg at mail.gmail.com...
> On Wed, Jun 11, 2014 at 1:19 AM, Frank Millman <frank at chagford.com> wrote:
>> First attempt - same as before
>>
>>     loop = asyncio.get_event_loop()
>>     threading.Thread(target=loop.run_forever).start()
>>     input('Press <enter> to stop')
>>     loop.stop()
>>     loop.close()
>
> Each event loop is hosted by a specific thread.  In this case you're
> getting the event loop of the main thread and then trying to run it in
> a separate thread, which is not a good idea.  You can run an event
> loop in a separate thread, but you should install a separate event
> loop for that thread if you do (and then when you interact with the
> loop, do so in a thread-safe manner -- see below).
>
>> Second attempt - move the keyboard input to a separate thread
>>
>>     def stop_loop():
>>         input('Press <enter> to stop')
>>         loop.stop()
>>         loop.close()
>>
>>     loop = asyncio.get_event_loop()
>>     threading.Thread(target=stop_loop).start()
>>     loop.run_forever()
>
> One issue here is that (like most event loop implementations) event
> loops are not thread-safe.  To make a call to the event loop across
> threads, you should be using the call_soon_threadsafe method, e.g.
> "loop.call_soon_threadsafe(loop.stop)".  You'll also want to make sure
> that the event loop has actually stopped before you call loop.close --
> see below.
>
>> Third attempt - get the loop to close itself (cannot use in practice, but
>> see what happens)
>>
>>     def stop_loop():
>>         loop.stop()
>>         loop.close()
>>
>>     loop = asyncio.get_event_loop()
>>     loop.call_later(2, stop_loop)
>>     loop.run_forever()
>
> I think what's happening here is that per the docs loop.close should
> not be called while the loop is running.  You've called loop.stop but
> you're still inside a callback, which is a bit of a gray area.  You
> probably don't need to call loop.close at all, but if you want to do
> so I suggest putting it after the run_forever call, so you can be
> certain the loop has stopped when it's called.
>
> Putting all that together, you should have something like this:
>
>    def stop_loop():
>        input('Press <enter> to stop')
>        loop.call_soon_threadsafe(loop.stop)
>
>    loop = asyncio.get_event_loop()
>    threading.Thread(target=stop_loop).start()
>    loop.run_forever()
>    loop.close()  # optional

Thanks very much for the very clear explanation.

Your solution works perfectly.

Much appreciated.

Frank






More information about the Python-list mailing list