首页 > 解决方案 > 是否可以屏蔽后台任务被 asyncio.run() 取消?

问题描述

假设我有一个应用程序处理队列中的一些任务。我希望能够中断/终止循环,但首先要完成任何消息的处理。

async def run():
    while True:
        msg = await queue.get()
        await asyncio.shield(process_msg(msg))
        # Or, maybe asyncio.create_task()

asyncio.run(run())

使用这样的代码,主任务将被中断并取消,但随后asyncio.run()会尝试取消所有剩余的任务,从而导致process_msg()任务被取消。

那么,有没有什么通用的方法可以防止任务在关机时被取消?这似乎是一种足够常见的设计模式,我希望它已经被考虑过,但我没有在网上找到任何东西。

使用低级 API,我目前想出了类似的东西来替换asyncio.run()

loop = asyncio.get_event_loop()
t = loop.create_task(run())
for s in (SIGINT, SIGTERM):
    loop.add_signal_handler(s, t.cancel)

with suppress(asyncio.CancelledError):
    loop.run_until_complete(t)
loop.run_until_complete(asyncio.gather(*asyncio.all_tasks(loop)))

对于这个简单的示例,这可能很好,但对于更复杂的应用程序,可能需要由处理取消asyncio.run()并有一种方法来保护特定任务免受关闭取消。

普遍的共识是asyncio.run()几乎所有时间都应该使用它,我们不应该为典型的应用程序需要低级 API,但这对我来说似乎是一个相当常见的应用程序设计。那么,我是否遗漏了一些可以适应这种方法的东西?

标签: pythonpython-asyncio

解决方案


推荐阅读