1

例子:

    with suppress(asyncio.CancelledError):
        [await t for t in asyncio.all_tasks(loop=self.loop)
            if t is not asyncio.current_task()]

为避免Task was destroyed but it is pending!警告,我必须在取消后等待任务,但等待它们会导致终端被CancelledError. 我知道它被取消了,但我不需要看到它。

在这里使用是否contextlib.suppress会对取消产生负面影响?我可以避免看到取消的错误(或任务被破坏的警告而无需等待)的唯一另一种方法是使用asyncio.wait而不是开始我的初始任务asyncio.gather。出于某种原因,wait似乎抑制了异常。我使用return_when=asyncio.FIRST_EXCEPTIONonwaitreturn_exceptions=Trueon gather。但似乎无论我如何设置他们的关键字参数,都会gather打印异常而wait没有。

4

1 回答 1

4

CancelledError在 asyncio 中用于两个目的:一个是发出取消请求的信号——这是你在协程中得到的那个被取消——另一个是发出取消响应的信号——这是你在等待任务的协程中得到的那个。抑制取消请求是一个坏主意,因为它会使协程无法响应取消,从而导致以后出现问题。但是抑制响应非常好,因为您可能希望等待取消的协程(例如,避免此警告)而不传播异常。

请注意,您所做的方式看起来不太正确,因为列表理解将在first CancelledError终止,因此您不会等待其他协程。正确的方法是放入suppress循环中,例如:

for t in tasks:
    with contextlib.suppress(asyncio.CancelledError):
        await t

# or, simpler:
await asyncio.gather(*tasks, return_exceptions=True)

wait()不会传播异常,因为它返回一组期货而不是它们的结果。如果您尝试访问返回的期货的结果,您会遇到异常。gather(return_exceptions=True)返回结果和异常的混合,它不应该引发任何事情。如果是这样,请编辑问题以提供一个最小的示例。

于 2021-01-28T07:34:27.787 回答