是否有类似于使用上下文管理器的 Pythonic 方式在后台运行异步任务?

Tom*_*auz 6 python contextmanager async-await python-asyncio

最近想在后台运行一些异步任务,同时运行其他任务,但我认为代码不够Pythonic

task = asyncio.create_task(long_task())
await short_task()
await task
Run Code Online (Sandbox Code Playgroud)

所以我让它更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()
Run Code Online (Sandbox Code Playgroud)

像这样的东西已经存在了吗?如果不是,这是否被认为比现有方式更 Pythonic 或更少 Pythonic?

use*_*342 5

这样的东西已经存在了吗?

目前还没有,但这是一个非常有用的想法。该概念的更通用版本将添加到Python 3.8(未来的 Python 版本)中,其形式是受CurioTrioTaskGroup中现有技术启发的类。

我建议增强 use 的实现finally,保证即使在出现异常的情况下也会等待后台任务;例如:

@asynccontextmanager
async def run_in_background(coro):
    task = asyncio.create_task(coro)
    try:
        yield task
    finally:
        await task
Run Code Online (Sandbox Code Playgroud)

如果不是,这是否被认为比现有方式更Pythonic 或更少Pythonic?

问题的这一部分显然是基于意见的,但我想说上下文管理器更Pythonic,因为它确保后台任务已完成并在块离开时等待。它还确保后台任务中的异常不会静默地传递,这是 asyncio 代码中错误的常见来源。


Tom*_*auz 1

trio提供了一种更好的方法来使用托儿所对象来做到这一点:

async with trio.open_nursery() as nursery:
    nursery.start_soon(long_task)  # Task will run in background

    await short_task()
    # Wait for background tasks to finish
Run Code Online (Sandbox Code Playgroud)