Recently I wanted to run some asynchronous tasks in the background while running other tasks but I didn't think the code was Pythonic enough:
task = asyncio.create_task(long_task())
await short_task()
await task
So I made it more Pythonic:
@asynccontextmanager
async def run_in_background(coro):
task = asyncio.create_task(coro)
yield task
await task
async def main():
async with run_in_background(long_task()):
await short_task()
Does something like this already exist? If not is this considered more Pythonic or less Pythonic than the existing way?
Does something like this already exist?
Not at the moment, but it's a very useful idea. A more general version of the concept will be added to Python 3.8 a future Python version in the form of a TaskGroup
class inspired by prior art in Curio and Trio.
I would suggest enhancing the implementation to use finally
, providing a guarantee that the background task will be awaited even in case of exception; for example:
@asynccontextmanager
async def run_in_background(coro):
task = asyncio.create_task(coro)
try:
yield task
finally:
await task
If not is this considered more Pythonic or less Pythonic than the existing way?
This part of the question is obviously opinion-based, but I would say a context manager is more Pythonic because it ensures that the background task is done and awaited by the time the block is left. It also ensures that the exceptions in the background task do not pass silently, which is a frequent source of bugs in asyncio code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With