Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doubt in spinner_async.py example #37

Open
CarMoreno opened this issue Aug 7, 2023 · 1 comment
Open

Doubt in spinner_async.py example #37

CarMoreno opened this issue Aug 7, 2023 · 1 comment

Comments

@CarMoreno
Copy link

CarMoreno commented Aug 7, 2023

Hi Luciano,

I am playing a bit with the spinner_async.py example, and I am wondering why the execution finishes normally when I comment the spinner.cancel() line in the supervisor function. I think the execution should stay in an infinite loop because I am not cancelling the coroutine and, therefore the asyncio.CancelledError exception is never raised.

async def supervisor() -> int:  # <3>
    spinner = asyncio.create_task(spin('thinking!'))  # <4>
    print(f'spinner object: {spinner}')  # <5>
    result = await slow()  # <6>
    #spinner.cancel()  # <------This is the only change <7>
    return result

I am forgetting something?, any comments to help me to understand this scenario are welcome.

@antonmosin
Copy link

antonmosin commented Nov 24, 2023

Hi @CarMoreno I'm just working through the chapter, let me test my thinking.

Based on pp.711-712, the program is not stuck in the infinite loop because:

  1. The execution of the main() is blocked until asyncio.run() returns.
  2. asyncio.run() will stop as soon as the the supervisor() returns the result.
  3. The supervisor() is blocked until slow() is running. Once slow() finishes, the evaluation proceeds to the return statement.

Thus, even though the spinner Task is not properly cancelled, the supervisor() returns the result which finishes the event loop that is controlled by the asyncio.run()

We can test this theory based on a slightly modified example from the Python documentation

import asyncio

async def cancel_me():
    print('cancel_me(): before sleep')

    try:
        # Wait for 1 hour
        await asyncio.sleep(3600)
    except asyncio.CancelledError:
        print('cancel_me(): cancel sleep')
        raise
    finally:
        print('cancel_me(): after sleep')

async def main():
    # Create a "cancel_me" Task
    task = asyncio.create_task(cancel_me())

    # Wait for 1 second
    await asyncio.sleep(1)

    #task.cancel()

asyncio.run(main())

# Expected output:
#
#     cancel_me(): before sleep
#     cancel_me(): cancel sleep
#     cancel_me(): after sleep
#     main(): cancel_me is cancelled now

Here I commented out the task.cancel() line, but the Task is still finalised by the asyncio.run() itself. From its docstring

This function always creates a new event loop and closes it at the end.
   It should be used as a main entry point for asyncio programs, and should
   ideally only be called once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants