python - What's the correct way to clean up after an interrupted event loop? -
i have event loop runs co-routines part of command line tool. user may interrupt tool usual ctrl + c, @ point want clean after interrupted event loop.
here's tried.
import asyncio @asyncio.coroutine def shleepy_time(seconds): print("shleeping {s} seconds...".format(s=seconds)) yield asyncio.sleep(seconds) if __name__ == '__main__': loop = asyncio.get_event_loop() # side note: apparently, async() deprecated in 3.4.4. # see: https://docs.python.org/3.4/library/asyncio-task.html#asyncio.async tasks = [ asyncio.async(shleepy_time(seconds=5)), asyncio.async(shleepy_time(seconds=10)) ] try: loop.run_until_complete(asyncio.gather(*tasks)) except keyboardinterrupt e: print("caught keyboard interrupt. canceling tasks...") # doesn't seem correct solution. t in tasks: t.cancel() finally: loop.close()
running , hitting ctrl + c yields:
$ python3 asyncio-keyboardinterrupt-example.py shleeping 5 seconds... shleeping 10 seconds... ^ccaught keyboard interrupt. canceling tasks... task destroyed pending! task: <task pending coro=<shleepy_time() running @ asyncio-keyboardinterrupt-example.py:7> wait_for=<future cancelled> cb=[gather.<locals>._done_callback(1)() @ /usr/local/cellar/python3/3.4.3/frameworks/python.framework/versions/3.4/lib/python3.4/asyncio/tasks.py:587]> task destroyed pending! task: <task pending coro=<shleepy_time() running @ asyncio-keyboardinterrupt-example.py:7> wait_for=<future cancelled> cb=[gather.<locals>._done_callback(0)() @ /usr/local/cellar/python3/3.4.3/frameworks/python.framework/versions/3.4/lib/python3.4/asyncio/tasks.py:587]>
clearly, didn't clean correctly. thought perhaps calling cancel()
on tasks way it.
what's correct way clean after interrupted event loop?
when ctrl+c, event loop gets stopped, calls t.cancel()
don't take effect. tasks cancelled, need start loop again.
here's how can handle it:
import asyncio @asyncio.coroutine def shleepy_time(seconds): print("shleeping {s} seconds...".format(s=seconds)) yield asyncio.sleep(seconds) if __name__ == '__main__': loop = asyncio.get_event_loop() # side note: apparently, async() deprecated in 3.4.4. # see: https://docs.python.org/3.4/library/asyncio-task.html#asyncio.async tasks = asyncio.gather( asyncio.async(shleepy_time(seconds=5)), asyncio.async(shleepy_time(seconds=10)) ) try: loop.run_until_complete(tasks) except keyboardinterrupt e: print("caught keyboard interrupt. canceling tasks...") tasks.cancel() loop.run_forever() tasks.exception() finally: loop.close()
once catch keyboardinterrupt
, call tasks.cancel()
, start loop
again. run_forever
exit tasks
gets cancelled (note cancelling future
returned asyncio.gather
cancels futures
inside of it), because interrupted loop.run_until_complete
call added done_callback
tasks
stops loop. so, when cancel tasks
, callback fires, , loop stops. @ point call tasks.exception
, avoid getting warning not fetching exception _gatheringfuture
.
Comments
Post a Comment