简体   繁体   中英

Why the while loop on asyncio task's done() method break even though the condition logic is always true?

I'm trying to understand this code:

async def delay(sec: int):
    print(f"delay() going to sleep for {sec}s")
    await asyncio.sleep(sec)
    print("delay() waked up")


async def main():
    task = asyncio.create_task(delay(5))

    seconds_elapsed = 0
    while not task.done():
        print(f"checking task finished... {task.done()}")
        await asyncio.sleep(1)
        seconds_elapsed += 1
        if seconds_elapsed == 3:
            print(f"cancelled result: {task.cancel()}")
            print(f"task is done: {task.done()}")

    print("main() awaiting task")
    try:
        # await task
        pass
    except asyncio.CancelledError:
        print("task was cancelled")
    print("main() finished")


asyncio.run(main())

The logs:

checking task finished... False
delay() going to sleep for 5s
checking task finished... False
checking task finished... False
cancelled result: True
task is done: False
checking task finished... False
main() awaiting task
main() finished

After 3s has passed, the task was canceled and the task.done() is still false, so the while loop continues with line 15... finally the while loop break at line 16 and print line 22.

Pls help me to explain why? I thought that the while loop should run forever because the task.done() will always be false.

Try running this slightly modified version of your code:

import asyncio

async def delay(sec: int):
    print(f"delay() going to sleep for {sec}s")
    await asyncio.sleep(sec)
    print("delay() waked up")


async def main():
    task = asyncio.create_task(delay(5))

    seconds_elapsed = 0
    while not task.done():
        print(f"checking task finished... {task.done()}")
        await asyncio.sleep(1)
        seconds_elapsed += 1
        if seconds_elapsed == 3:
            print(f"cancelled result: {task.cancel()}")
            print(f"task is done: {task.done()}")
        print(f"Check task again: {task.done()}")

    print("main() awaiting task")
    try:
        # await task
        pass
    except asyncio.CancelledError:
        print("task was cancelled")
    print("main() finished")


asyncio.run(main())

You may notice that the output is now

checking task finished... False
delay() going to sleep for 5s
Check task again: False
checking task finished... False
Check task again: False
checking task finished... False
cancelled result: True
task is done: False
Check task again: False
checking task finished... False
Check task again: True # Look here!!!
main() awaiting task
main() finished

This is because you are calling task.cancel() after 3 seconds. This call successfully cancels the delay call, but it takes a moment for the status of the task to be set to done. If you remove the call to task.cancel() the while loop will run for the full 5 second delay you set.

import asyncio

async def delay(sec: int):
    print(f"delay() going to sleep for {sec}s")
    await asyncio.sleep(sec)
    print("delay() waked up")


async def main():
    task = asyncio.create_task(delay(5))

    seconds_elapsed = 0
    while not task.done():
        print(f"checking task finished... {task.done()}")
        await asyncio.sleep(1)
        seconds_elapsed += 1
        if seconds_elapsed == 3:
            print(f"task is done: {task.done()}")

    print("main() awaiting task")
    try:
        # await task
        pass
    except asyncio.CancelledError:
        print("task was cancelled")
    print("main() finished")


asyncio.run(main())

Output:

checking task finished... False
delay() going to sleep for 5s
checking task finished... False
checking task finished... False
task is done: False
checking task finished... False
checking task finished... False
delay() waked up
main() awaiting task
main() finished

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM