Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Pythonic way to run async task in background similar to using a contextmanager?

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?

like image 235
Tom Gringauz Avatar asked Sep 04 '18 01:09

Tom Gringauz


1 Answers

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.

like image 194
user4815162342 Avatar answered Oct 06 '22 00:10

user4815162342