["python","python-3.5","python-asyncio"]
"Fire and forget" python async/await

Sometimes there is some non-critical asynchronous operation that needs to happen but I don't want to wait for it to complete. In Tornado's coroutine implementation you can "fire & forget" an asynchronous function by simply ommitting the yield key-word. I've been trying to figure out how to "fire & forget" with the new async/await syntax released in Python 3.5. E.g., a simplified code snippet: async def async_foo(): print("Do some stuff asynchronously here...") def bar(): async_foo() # fire and forget "async_foo()" bar() What happens though is that bar() never executes and instead we get a runtime warning: RuntimeWarning: coroutine 'async_foo' was never awaited async_foo() # fire and forget "async_foo()"
Editor's note: According to a comment below, According to the documentation the event loop only keeps a "weak reference" to a task, see https://docs.python.org/3.13/library/asyncio-task.html#creating-tasks so it appears to me that you MUST save a reference in order to ensure that the task is not destroyed before it is done. It seems to me that this makes this answer wrong. Upd: Replace asyncio.ensure_future with asyncio.create_task everywhere if you're using Python >= 3.7 It's a newer, nicer way to spawn tasks. asyncio.Task to "fire and forget" According to python docs for asyncio.Task it is possible to start some coroutine to execute "in the background". The task created by asyncio.ensure_future won't block the execution (therefore the function will return immediately!). This looks like a way to "fire and forget" as you requested. import asyncio async def async_foo(): print("async_foo started") await asyncio.sleep(1) print("async_foo done") async def main(): asyncio.ensure_future(async_foo()) # fire and forget async_foo() # btw, you can also create tasks inside non-async funcs print('Do some actions 1') await asyncio.sleep(1) print('Do some actions 2') await asyncio.sleep(1) print('Do some actions 3') if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(main()) Output: Do some actions 1 async_foo started Do some actions 2 async_foo done Do some actions 3 What if tasks are executing after the event loop has completed? Note that asyncio expects tasks to be completed at the moment the event loop completes. So if you'll change main() to: async def main(): asyncio.ensure_future(async_foo()) # fire and forget print('Do some actions 1') await asyncio.sleep(0.1) print('Do some actions 2') You'll get this warning after the program finished: Task was destroyed but it is pending! task: <Task pending coro=<async_foo() running at [...] To prevent that you can just await all pending tasks after the event loop has completed: async def main(): asyncio.ensure_future(async_foo()) # fire and forget print('Do some actions 1') await asyncio.sleep(0.1) print('Do some actions 2') if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(main()) # Let's also finish all running tasks: pending = asyncio.Task.all_tasks() loop.run_until_complete(asyncio.gather(*pending)) Kill tasks instead of awaiting them Sometimes you don't want to await tasks to be done (for example, some tasks may be created to run forever). In that case, you can just cancel() them instead of awaiting them: import asyncio from contextlib import suppress async def echo_forever(): while True: print("echo") await asyncio.sleep(1) async def main(): asyncio.ensure_future(echo_forever()) # fire and forget print('Do some actions 1') await asyncio.sleep(1) print('Do some actions 2') await asyncio.sleep(1) print('Do some actions 3') if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(main()) # Let's also cancel all running tasks: pending = asyncio.Task.all_tasks() for task in pending: task.cancel() # Now we should await task to execute it's cancellation. # Cancelled task raises asyncio.CancelledError that we can suppress: with suppress(asyncio.CancelledError): loop.run_until_complete(task) Output: Do some actions 1 echo Do some actions 2 echo Do some actions 3 echo