Python asyncio 任务取消消息未传播

Python asyncio task cancel message not propagated

提问人:Claudio_G 提问时间:11/15/2023 最后编辑:Claudio_G 更新时间:11/15/2023 访问量:26

问:

我很难理解异步是如何的。CancelledError 正在传播。我有以下代码:

import asyncio
import traceback


async def uselessTask():
    return await asyncio.sleep(10)


async def mainAsync():
    task = asyncio.create_task(uselessTask())
    asyncio.get_running_loop().call_later(1, lambda: task.cancel("CANCELLING USELESS TASK"))

    try:
        results = await task

    except asyncio.CancelledError as exc:
        print(f"Caught exception {type(exc).__name__}: {exc}")
        print(f"Task: {task}")
        traceback.print_exc()

    return

asyncio.run(mainAsync())

上述操作的执行会产生以下结果(对于 python 3.9.6 和 3.10.7):

Caught exception CancelledError: 
Task: <Task cancelled name='Task-2' coro=<uselessTask() done, defined at C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py:5>>
Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 6, in uselessTask
    return await asyncio.sleep(10)
  File "C:\Users\<user>\AppData\Local\Programs\Python\Python310\lib\asyncio\tasks.py", line 605, in sleep
    return await future
asyncio.exceptions.CancelledError: CANCELLING USELESS TASK

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 14, in mainAsync
    results = await task
asyncio.exceptions.CancelledError

Process finished with exit code 0

但是,我的期望是,在执行期间捕获的异常与任务中发生的异常完全相同,因此会显示相同的取消消息“取消无用任务”。results = await task

但是,正如您所看到的,asyncio 上没有取消消息。CancelledError 由使用任务导致。

我不明白的另一件奇怪的事情是,如果我打破异常块并检查变量,我会看到任务被取消,但_cancel_message是空的。task

no cancellation message

我不完全理解为什么异常会以这种方式冒泡,或者为什么除了在任务中之外看不到取消消息(例如,如果我尝试:除了:uselessTask()函数,则捕获的异常有消息)。此外,回溯消息“在处理上述异常期间,发生了另一个异常:”似乎表明没有发生异常链接,因为链接产生“上述异常是以下异常的直接原因:”

我正在浏览 python 文档,但我似乎无法将我所看到的内容与所写的内容相关联。

编辑:

只是为了更好地展示我的期望:

import asyncio
import traceback


async def uselessTask():
    try:
        await asyncio.sleep(10)
    except asyncio.CancelledError as exc:
        raise RuntimeError(*exc.args)

    return



async def mainAsync():
    task = asyncio.create_task(uselessTask())
    asyncio.get_running_loop().call_later(1, lambda: task.cancel("CANCELLING USELESS TASK"))

    try:
        results = await task

    except (asyncio.CancelledError, RuntimeError) as exc:
        print(f"Caught exception {type(exc).__name__}: {exc}")
        print(f"Task: {task}")
        traceback.print_exc()

    return

asyncio.run(mainAsync())

此代码返回

Caught exception RuntimeError: CANCELLING USELESS TASK
Task: <Task finished name='Task-2' coro=<uselessTask() done, defined at C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py:5> exception=RuntimeError('CANCELLING USELESS TASK')>
Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 7, in uselessTask
    await asyncio.sleep(10)
  File "C:\Users\<user>\AppData\Local\Programs\Python\Python310\lib\asyncio\tasks.py", line 605, in sleep
    return await future
asyncio.exceptions.CancelledError: CANCELLING USELESS TASK

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 20, in mainAsync
    results = await task
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 9, in uselessTask
    raise RuntimeError(*exc.args)
RuntimeError: CANCELLING USELESS TASK

Process finished with exit code 0

另一方面,此代码

import asyncio
import traceback


async def uselessTask():
    try:
        await asyncio.sleep(10)
    except asyncio.CancelledError as exc:
        raise asyncio.CancelledError(*exc.args)

    return



async def mainAsync():
    task = asyncio.create_task(uselessTask())
    asyncio.get_running_loop().call_later(1, lambda: task.cancel("CANCELLING USELESS TASK"))

    try:
        results = await task

    except (asyncio.CancelledError, RuntimeError) as exc:
        print(f"Caught exception {type(exc).__name__}: {exc}")
        print(f"Task: {task}")
        traceback.print_exc()

    return

asyncio.run(mainAsync())

返回以下内容:

Caught exception CancelledError: 
Task: <Task cancelled name='Task-2' coro=<uselessTask() done, defined at C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py:5>>
Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 7, in uselessTask
    await asyncio.sleep(10)
  File "C:\Users\<user>\AppData\Local\Programs\Python\Python310\lib\asyncio\tasks.py", line 605, in sleep
    return await future
asyncio.exceptions.CancelledError: CANCELLING USELESS TASK

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 9, in uselessTask
    raise asyncio.CancelledError(*exc.args)
asyncio.exceptions.CancelledError: CANCELLING USELESS TASK

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\<user>\AppData\Roaming\JetBrains\PyCharmCE2022.2\scratches\scratch_22.py", line 20, in mainAsync
    results = await task
asyncio.exceptions.CancelledError

Process finished with exit code 0

如您所见,解开任务结果会引发 asyncio。CancelledError,但消息现在已消失,而在引发任何其他异常时,解包会保留 Exception 参数

python-asyncio 取消

评论


答: 暂无答案