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;
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
add a comment |
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
1
Theawait future
statement raises an asyncio.CancelledError exception. Use atry/except
statement if you want to ignore the cancellation.
– Vincent
Nov 16 '18 at 14:35
add a comment |
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
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
future python-asyncio
asked Nov 16 '18 at 13:41
JSStuballJSStuball
622416
622416
1
Theawait future
statement raises an asyncio.CancelledError exception. Use atry/except
statement if you want to ignore the cancellation.
– Vincent
Nov 16 '18 at 14:35
add a comment |
1
Theawait future
statement raises an asyncio.CancelledError exception. Use atry/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
add a comment |
1 Answer
1
active
oldest
votes
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
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
add a comment |
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
add a comment |
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
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
answered Nov 16 '18 at 14:30
user4815162342user4815162342
64.7k595151
64.7k595151
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
1
The
await future
statement raises an asyncio.CancelledError exception. Use atry/except
statement if you want to ignore the cancellation.– Vincent
Nov 16 '18 at 14:35