When you CTRL+C, the event loop gets stopped, so your calls to t.cancel()
don’t actually take effect. For the tasks to be cancelled, you need to start the loop back up again.
Here’s how you can handle it:
import asyncio
@asyncio.coroutine
def shleepy_time(seconds):
print("Shleeping for {s} seconds...".format(s=seconds))
yield from asyncio.sleep(seconds)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
# Side note: Apparently, async() will be 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 as e:
print("Caught keyboard interrupt. Canceling tasks...")
tasks.cancel()
loop.run_forever()
tasks.exception()
finally:
loop.close()
Once we catch KeyboardInterrupt
, we call tasks.cancel()
and then start the loop
up again. run_forever
will actually exit as soon as tasks
gets cancelled (note that cancelling the Future
returned by asyncio.gather
also cancels all the Futures
inside of it), because the interrupted loop.run_until_complete
call added a done_callback
to tasks
that stops the loop. So, when we cancel tasks
, that callback fires, and the loop stops. At that point we call tasks.exception
, just to avoid getting a warning about not fetching the exception from the _GatheringFuture
.