首页 > 解决方案 > 我是否正在处理一个忽略 CancelledError 的异步任务?

问题描述

我不是在问如何取消这样的任务。这是不可能的,它在这里解释:https ://stackoverflow.com/a/33578893/5378816

我担心的是wait_for的这种变化:

在 3.7 版更改: 当 aw 由于超时而被取消时,wait_for 等待 aw 被取消。以前,它会立即引发 asyncio.TimeoutError。

不要误会我的意思,我喜欢它,这是一种改进。

但是,该程序现在将挂起wait_for(Python 3.7):

import asyncio

async def uncancellable():
    while True:
        try:
            await asyncio.sleep(99)
        except asyncio.CancelledError:
            print("sorry!")

TIMEOUT = 1.0

async def test():
    task = asyncio.get_event_loop().create_task(uncancellable())
    try:
        await asyncio.wait_for(task, TIMEOUT)
    except asyncio.TimeoutError:
        print("timeout")

asyncio.get_event_loop().run_until_complete(test())

不可取消的任务是编程错误。但是如果我需要防御,我该如何防止wait_for无限期挂起?

我试过这个。第一次超时:取消前,第二次超时:放弃前。

await asyncio.wait_for(asyncio.wait_for(task, TIMEOUT1), TIMEOUT1+TIMEOUT2)

有一个小问题我不太关心。当它出现时,asyncio.TimeoutError我无法判断它是在第一次超时还是在第二次超时时发生的。基本上我认为它有效,但它真的正确吗?

标签: pythonpython-asyncio

解决方案


但是如果我需要防御,我如何防止 wait_for 无限期挂起?

我不认为将每项任务都视为可能无法取消是一个好主意。

通常你只是假设这种情况不会发生并且没关系,因为,是的,不可取消的任务是一个编程错误,它不是你期望经常看到的一种错误。同样的方式,您通常不会期望某些内部代码会抑制KeyboardInterrupt任何其他 BaseException.

期望第三方代码遵循某些合同并没有错(例如上面的示例,或者说不是随机调用sys.exit())。否则,您将不得不编写更多代码,并且可能仍然无法涵盖所有​​可能的情况。


推荐阅读