"Ian Kelly" <ian.g.ke...@gmail.com> wrote in message news:CALwzidnv07Wba9WJ=nuc0_v4mvudyaxwh6bgjvw0o1hf3oo...@mail.gmail.com... > On Wed, Jun 11, 2014 at 1:19 AM, Frank Millman <fr...@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 -- https://mail.python.org/mailman/listinfo/python-list