Is it ever useful to cancel an asyncio future?



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








0















I am trying to understand the use of Future.cancel() with asyncio. The Python documentation is very light on this. I've had no success with existing questions on here or search engines. I just want to understand happens when a task is awaiting a future which is cancelled.



Here is my code:



import asyncio 

async def foo(future):
await asyncio.sleep(3)
future.cancel()

async def bar(future):
await future
print("hi")

async def baz(future):
await bar(future)
print("ho")

loop = asyncio.get_event_loop()
future = loop.create_future()
loop.create_task(baz(future))
loop.create_task(foo(future))
loop.run_forever()


"hi" is not seen printed. So I initially guessed bar was returning at the line await future in the case of a cancel.



However, "ho" is not printed either. So it seems logical that cancelling a future never yields back to tasks awaiting it? But then these tasks are sitting in the event loop forever? This seems undesirable, where have I misunderstood?










share|improve this question

















  • 1





    The await future statement raises an asyncio.CancelledError exception. Use a try/except statement if you want to ignore the cancellation.

    – Vincent
    Nov 16 '18 at 14:35

















0















I am trying to understand the use of Future.cancel() with asyncio. The Python documentation is very light on this. I've had no success with existing questions on here or search engines. I just want to understand happens when a task is awaiting a future which is cancelled.



Here is my code:



import asyncio 

async def foo(future):
await asyncio.sleep(3)
future.cancel()

async def bar(future):
await future
print("hi")

async def baz(future):
await bar(future)
print("ho")

loop = asyncio.get_event_loop()
future = loop.create_future()
loop.create_task(baz(future))
loop.create_task(foo(future))
loop.run_forever()


"hi" is not seen printed. So I initially guessed bar was returning at the line await future in the case of a cancel.



However, "ho" is not printed either. So it seems logical that cancelling a future never yields back to tasks awaiting it? But then these tasks are sitting in the event loop forever? This seems undesirable, where have I misunderstood?










share|improve this question

















  • 1





    The await future statement raises an asyncio.CancelledError exception. Use a try/except statement if you want to ignore the cancellation.

    – Vincent
    Nov 16 '18 at 14:35













0












0








0








I am trying to understand the use of Future.cancel() with asyncio. The Python documentation is very light on this. I've had no success with existing questions on here or search engines. I just want to understand happens when a task is awaiting a future which is cancelled.



Here is my code:



import asyncio 

async def foo(future):
await asyncio.sleep(3)
future.cancel()

async def bar(future):
await future
print("hi")

async def baz(future):
await bar(future)
print("ho")

loop = asyncio.get_event_loop()
future = loop.create_future()
loop.create_task(baz(future))
loop.create_task(foo(future))
loop.run_forever()


"hi" is not seen printed. So I initially guessed bar was returning at the line await future in the case of a cancel.



However, "ho" is not printed either. So it seems logical that cancelling a future never yields back to tasks awaiting it? But then these tasks are sitting in the event loop forever? This seems undesirable, where have I misunderstood?










share|improve this question














I am trying to understand the use of Future.cancel() with asyncio. The Python documentation is very light on this. I've had no success with existing questions on here or search engines. I just want to understand happens when a task is awaiting a future which is cancelled.



Here is my code:



import asyncio 

async def foo(future):
await asyncio.sleep(3)
future.cancel()

async def bar(future):
await future
print("hi")

async def baz(future):
await bar(future)
print("ho")

loop = asyncio.get_event_loop()
future = loop.create_future()
loop.create_task(baz(future))
loop.create_task(foo(future))
loop.run_forever()


"hi" is not seen printed. So I initially guessed bar was returning at the line await future in the case of a cancel.



However, "ho" is not printed either. So it seems logical that cancelling a future never yields back to tasks awaiting it? But then these tasks are sitting in the event loop forever? This seems undesirable, where have I misunderstood?







future python-asyncio






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 16 '18 at 13:41









JSStuballJSStuball

622416




622416







  • 1





    The await future statement raises an asyncio.CancelledError exception. Use a try/except statement if you want to ignore the cancellation.

    – Vincent
    Nov 16 '18 at 14:35












  • 1





    The await future statement raises an asyncio.CancelledError exception. Use a try/except statement if you want to ignore the cancellation.

    – Vincent
    Nov 16 '18 at 14:35







1




1





The await future statement raises an asyncio.CancelledError exception. Use a try/except statement if you want to ignore the cancellation.

– Vincent
Nov 16 '18 at 14:35





The await future statement raises an asyncio.CancelledError exception. Use a try/except statement if you want to ignore the cancellation.

– Vincent
Nov 16 '18 at 14:35












1 Answer
1






active

oldest

votes


















1














In this case the answer lies in the documentation, but you have to look for it a bit. First, a reminder of what it means to await a future:



# the expression:
x = await future

# is equivalent to:
... magically suspend the coroutine until the future.done() becomes true ...
x = future.result()


In other words, once the execution of the coroutine that contains await resumes, the value of the await statement will be the result() of the awaited future.



The question is: when you cancel a future, what is its result? The documentation says:




If the Future has been cancelled, this method raises a CancelledError exception.




So when someone cancel a future you awaited, the await future expression will raise an exception! This neatly explains why bar doesn't print hi (because await future has raised), and why baz doesn't print ho (because await bar(...) has raised).



A traceback is never printed because loop.create_task spawns the coroutine in the "background" (of sorts) - if no one inspects the return value, the exception will be lost. And since you threw away the task object returned by create_task and used run_forever to have the loop running forever, the loop just continues running, waiting (forever) for new tasks to somehow arrive.



If you changed the code to actually collect the result of bar, you would easily observe the CancelledError:



if __name__ == '__main__':
loop = asyncio.get_event_loop()
future = loop.create_future()
loop.create_task(foo(future))
loop.run_until_complete(baz(future))


Output:



Traceback (most recent call last):
File "xxx.py", line 19, in <module>
loop.run_until_complete(baz(future))
File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
return future.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 266, in result
raise CancelledError
concurrent.futures._base.CancelledError





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53339025%2fis-it-ever-useful-to-cancel-an-asyncio-future%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    In this case the answer lies in the documentation, but you have to look for it a bit. First, a reminder of what it means to await a future:



    # the expression:
    x = await future

    # is equivalent to:
    ... magically suspend the coroutine until the future.done() becomes true ...
    x = future.result()


    In other words, once the execution of the coroutine that contains await resumes, the value of the await statement will be the result() of the awaited future.



    The question is: when you cancel a future, what is its result? The documentation says:




    If the Future has been cancelled, this method raises a CancelledError exception.




    So when someone cancel a future you awaited, the await future expression will raise an exception! This neatly explains why bar doesn't print hi (because await future has raised), and why baz doesn't print ho (because await bar(...) has raised).



    A traceback is never printed because loop.create_task spawns the coroutine in the "background" (of sorts) - if no one inspects the return value, the exception will be lost. And since you threw away the task object returned by create_task and used run_forever to have the loop running forever, the loop just continues running, waiting (forever) for new tasks to somehow arrive.



    If you changed the code to actually collect the result of bar, you would easily observe the CancelledError:



    if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    future = loop.create_future()
    loop.create_task(foo(future))
    loop.run_until_complete(baz(future))


    Output:



    Traceback (most recent call last):
    File "xxx.py", line 19, in <module>
    loop.run_until_complete(baz(future))
    File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
    return future.result()
    File "/usr/lib/python3.5/asyncio/futures.py", line 266, in result
    raise CancelledError
    concurrent.futures._base.CancelledError





    share|improve this answer



























      1














      In this case the answer lies in the documentation, but you have to look for it a bit. First, a reminder of what it means to await a future:



      # the expression:
      x = await future

      # is equivalent to:
      ... magically suspend the coroutine until the future.done() becomes true ...
      x = future.result()


      In other words, once the execution of the coroutine that contains await resumes, the value of the await statement will be the result() of the awaited future.



      The question is: when you cancel a future, what is its result? The documentation says:




      If the Future has been cancelled, this method raises a CancelledError exception.




      So when someone cancel a future you awaited, the await future expression will raise an exception! This neatly explains why bar doesn't print hi (because await future has raised), and why baz doesn't print ho (because await bar(...) has raised).



      A traceback is never printed because loop.create_task spawns the coroutine in the "background" (of sorts) - if no one inspects the return value, the exception will be lost. And since you threw away the task object returned by create_task and used run_forever to have the loop running forever, the loop just continues running, waiting (forever) for new tasks to somehow arrive.



      If you changed the code to actually collect the result of bar, you would easily observe the CancelledError:



      if __name__ == '__main__':
      loop = asyncio.get_event_loop()
      future = loop.create_future()
      loop.create_task(foo(future))
      loop.run_until_complete(baz(future))


      Output:



      Traceback (most recent call last):
      File "xxx.py", line 19, in <module>
      loop.run_until_complete(baz(future))
      File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
      return future.result()
      File "/usr/lib/python3.5/asyncio/futures.py", line 266, in result
      raise CancelledError
      concurrent.futures._base.CancelledError





      share|improve this answer

























        1












        1








        1







        In this case the answer lies in the documentation, but you have to look for it a bit. First, a reminder of what it means to await a future:



        # the expression:
        x = await future

        # is equivalent to:
        ... magically suspend the coroutine until the future.done() becomes true ...
        x = future.result()


        In other words, once the execution of the coroutine that contains await resumes, the value of the await statement will be the result() of the awaited future.



        The question is: when you cancel a future, what is its result? The documentation says:




        If the Future has been cancelled, this method raises a CancelledError exception.




        So when someone cancel a future you awaited, the await future expression will raise an exception! This neatly explains why bar doesn't print hi (because await future has raised), and why baz doesn't print ho (because await bar(...) has raised).



        A traceback is never printed because loop.create_task spawns the coroutine in the "background" (of sorts) - if no one inspects the return value, the exception will be lost. And since you threw away the task object returned by create_task and used run_forever to have the loop running forever, the loop just continues running, waiting (forever) for new tasks to somehow arrive.



        If you changed the code to actually collect the result of bar, you would easily observe the CancelledError:



        if __name__ == '__main__':
        loop = asyncio.get_event_loop()
        future = loop.create_future()
        loop.create_task(foo(future))
        loop.run_until_complete(baz(future))


        Output:



        Traceback (most recent call last):
        File "xxx.py", line 19, in <module>
        loop.run_until_complete(baz(future))
        File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
        return future.result()
        File "/usr/lib/python3.5/asyncio/futures.py", line 266, in result
        raise CancelledError
        concurrent.futures._base.CancelledError





        share|improve this answer













        In this case the answer lies in the documentation, but you have to look for it a bit. First, a reminder of what it means to await a future:



        # the expression:
        x = await future

        # is equivalent to:
        ... magically suspend the coroutine until the future.done() becomes true ...
        x = future.result()


        In other words, once the execution of the coroutine that contains await resumes, the value of the await statement will be the result() of the awaited future.



        The question is: when you cancel a future, what is its result? The documentation says:




        If the Future has been cancelled, this method raises a CancelledError exception.




        So when someone cancel a future you awaited, the await future expression will raise an exception! This neatly explains why bar doesn't print hi (because await future has raised), and why baz doesn't print ho (because await bar(...) has raised).



        A traceback is never printed because loop.create_task spawns the coroutine in the "background" (of sorts) - if no one inspects the return value, the exception will be lost. And since you threw away the task object returned by create_task and used run_forever to have the loop running forever, the loop just continues running, waiting (forever) for new tasks to somehow arrive.



        If you changed the code to actually collect the result of bar, you would easily observe the CancelledError:



        if __name__ == '__main__':
        loop = asyncio.get_event_loop()
        future = loop.create_future()
        loop.create_task(foo(future))
        loop.run_until_complete(baz(future))


        Output:



        Traceback (most recent call last):
        File "xxx.py", line 19, in <module>
        loop.run_until_complete(baz(future))
        File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
        return future.result()
        File "/usr/lib/python3.5/asyncio/futures.py", line 266, in result
        raise CancelledError
        concurrent.futures._base.CancelledError






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 16 '18 at 14:30









        user4815162342user4815162342

        64.7k595151




        64.7k595151





























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53339025%2fis-it-ever-useful-to-cancel-an-asyncio-future%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Top Tejano songwriter Luis Silva dead of heart attack at 64

            ReactJS Fetched API data displays live - need Data displayed static

            政党