热门标签:
Q:

Python asyncio:取消任务的竞争条件

I python示例(https://docs.python.org/3/library/asyncio-task.html#asyncio.Task.cancel),一个任务可以像下面的代码片段中一样取消:

task.cancel()
try:
   await task
except asyncio.CancelledError:
   print("main(): cancel_me is cancelled now")

但是当任务本身被取消与取消另一个任务相同时,这可能会导致竞争条件。 我已经添加了一个通过一个addition await语句导致此问题的示例await asyncio.sleep(0)

import asyncio


async def subtask(i: int):
    try:
        print(f"        subtask {i}: start")
        await asyncio.sleep(2)
    except asyncio.CancelledError:
        print(f"        subtask {i}: Clean Up")
        raise


async def handling():
    i = 0
    while True:
        print(f"    handling {i}: start")
        sub_task = asyncio.create_task(subtask(i))
        await asyncio.sleep(1)
        print(f"    handling {i}: cancel subtask")
        sub_task.cancel()  # (1) There is a reason why subtask must be canceled, but another must be restarted.
        try:
            await sub_task  # (2)
        except asyncio.CancelledError:
            print(f"    handling {i}: subtask canceled {sub_task.cancelled()}")
        print(f"    handling {i}: end")
        i += 1


async def main():
    print("main: start")
    handling_task = asyncio.create_task(handling())
    await asyncio.sleep(1)
    await asyncio.sleep(0)  # (3) This addition await call forces that handling_task is cancel at the same as calling (2)
    print("main: cancel")
    handling_task.cancel()  # handling_task must be canceled by a reason at the same time as the other task was canceled by a reason (1)
    try:
        await handling_task
    except asyncio.CancelledError:
        print(f"main: CancelledError. Task canceled {handling_task.cancelled()}.")
        pass  # Task was cancelled correctly
    print("main: end")


asyncio.run(main())

所以我的猜测是,它永远不允许抓住一个取消任务的CancelledError?

原网址

相似问题