【问题标题】:Is there a Pythonic way to run async task in background similar to using a contextmanager?是否有类似于使用上下文管理器的 Pythonic 方式在后台运行异步任务?
【发布时间】:2019-02-08 23:17:16
【问题描述】:

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

task = asyncio.create_task(long_task())
await short_task()
await task

所以我把它做得更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()

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

【问题讨论】:

  • 采用简短的东西并完成工作并转换为更大和更复杂的东西绝对不是 Pythonic。
  • @Keith 它是如何更大更复杂的? 2 线对 3。
  • @Keith 与使用with open("file")file.open file.close 相同。
  • @Keith 是的,但这就是实现,我写了一次,然后我可以在任何地方使用它。如果有这样的现有方式,我不需要编写新函数。好像你错过了我的问题的重点。
  • 这只是一个一般性的观察。这个问题实际上是模糊的,因为“Pythonic”也有点主观,并且您实际上并没有在异步框架中“在后台”运行任务。它只是事件循环的一部分,可以阻止它。

标签: python async-await python-asyncio contextmanager


【解决方案1】:

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

目前没有,但这是一个非常有用的想法。该概念的更通用版本将添加到 Python 3.8 未来的 Python 版本中,其形式为 TaskGroup 类,其灵感来自 CurioTrio 中的现有技术。

我建议增强实现以使用finally,保证即使出现异常也会等待后台任务;例如:

@asynccontextmanager
async def run_in_background(coro):
    task = asyncio.create_task(coro)
    try:
        yield task
    finally:
        await task

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

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

【讨论】:

  • 谢谢!等不及 python 3.8 了!
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-02
    • 1970-01-01
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 2018-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多