Issue30048
Created on 2017-04-12 00:11 by abacabadabacaba, last changed 2022-04-11 14:58 by admin. This issue is now closed.
| Pull Requests | |||
|---|---|---|---|
| URL | Status | Linked | Edit |
| PR 1097 | merged | methane, 2017-04-13 01:26 | |
| PR 1546 | merged | methane, 2017-05-11 12:24 | |
| PR 1547 | merged | methane, 2017-05-11 12:37 | |
| Messages (11) | |||
|---|---|---|---|
| msg291522 - (view) | Author: Evgeny Kapun (abacabadabacaba) | Date: 2017-04-12 00:11 | |
If I run this code:
import asyncio as a
@a.coroutine
def coro1():
yield from a.ensure_future(coro2())
print("Still here")
yield from a.sleep(1)
print("Still here 2")
@a.coroutine
def coro2():
yield from a.sleep(1)
res = task.cancel()
print("Canceled task:", res)
loop = a.get_event_loop()
task = a.ensure_future(coro1())
loop.run_until_complete(task)
I expect the task to stop shortly after a call to cancel(). It should surely stop when I try to sleep(). But it doesn't. On my machine this prints:
Canceled task: True
Still here
Still here 2
So, cancel() returns True, but the task doesn't seem to be canceled.
|
|||
| msg291523 - (view) | Author: Yury Selivanov (yselivanov) * ![]() |
Date: 2017-04-12 00:47 | |
Interesting. It doesn't work for both C and Python versions of the Task. I'll take a look in detail when I return from vacation. |
|||
| msg291528 - (view) | Author: Inada Naoki (methane) * ![]() |
Date: 2017-04-12 08:18 | |
When task.cancel() called, CancelledError is thrown to coro2.
But coro2 doesn't call `yield from` after task.cancel().
So the exception is never raised.
If you add `yield from` after `task.cancel()`, the script runs expected.
---
$ cat at.py
import asyncio as a
@a.coroutine
def coro1():
yield from a.ensure_future(coro2())
print("Still here")
yield from a.sleep(.1)
print("Still here 2")
@a.coroutine
def coro2():
yield from a.sleep(.1)
res = task.cancel()
print("Canceled task:", res)
yield from a.sleep(.1) # !!! added this line
loop = a.get_event_loop()
task = a.ensure_future(coro1())
loop.run_until_complete(task)
$ ./python.exe at.py
Canceled task: True
Traceback (most recent call last):
File "at.py", line 19, in <module>
loop.run_until_complete(task)
File "/Users/inada-n/work/python/cpython/Lib/asyncio/base_events.py", line 465, in run_until_complete
return future.result()
concurrent.futures._base.CancelledError
|
|||
| msg291531 - (view) | Author: Inada Naoki (methane) * ![]() |
Date: 2017-04-12 08:46 | |
This behavior is documented as: https://docs.python.org/3.6/library/asyncio-task.html#asyncio.Task.cancel > Unlike Future.cancel(), this does not guarantee that the task will be cancelled: the exception might be caught and acted upon, delaying cancellation of the task or preventing cancellation completely. The task may also return a value or raise a different exception. > > Immediately after this method is called, cancelled() will not return True (unless the task was already cancelled). A task will be marked as cancelled when the wrapped coroutine terminates with a CancelledError exception (even if cancel() was not called). I agree that this behavior is somewhat surprising. But I don't know how can I fix the behavior. |
|||
| msg291577 - (view) | Author: Evgeny Kapun (abacabadabacaba) | Date: 2017-04-12 23:11 | |
The problem is that the task doesn't catch CancelledError, yet it disappears. |
|||
| msg291578 - (view) | Author: Inada Naoki (methane) * ![]() |
Date: 2017-04-13 00:19 | |
> The problem is that the task doesn't catch CancelledError, yet it disappears.
The problem is CancelledError is not raised, even it's thrown.
Task can't catch exception not raised. See below example which demonstrates how task works.
---
from asyncio import CancelledError
cancelled = False
def coro():
global cancelled
print(1)
yield (1,)
print("cancel")
cancelled = True
#print(2)
#yield (2,) # uncomment this line makes cancel success.
c = coro()
while True:
try:
if cancelled:
r = c.throw(CancelledError)
else:
r = c.send(None)
except StopIteration:
print("end")
break
except CancelledError:
print("cancelled")
break
|
|||
| msg291579 - (view) | Author: Yury Selivanov (yselivanov) * ![]() |
Date: 2017-04-13 00:44 | |
In Evgeny's example the 'task' is 'coro1' (not 'coro2'). It has plenty of yield points after being cancelled. |
|||
| msg291580 - (view) | Author: Inada Naoki (methane) * ![]() |
Date: 2017-04-13 01:07 | |
> In Evgeny's example the 'task' is 'coro1' (not 'coro2'). It has plenty of yield points after being cancelled. Since coro1 waiting coro2 when cancelling, Task(coro1).cancel() redirect to Task(coro2).cancel(). But I was wrong about "CancelledError is thrown to coro2." Task(coro2) is cancelled in last step. CancelledError is not thrown to coro2 actually. So there is chance to detect it. |
|||
| msg293492 - (view) | Author: Inada Naoki (methane) * ![]() |
Date: 2017-05-11 12:18 | |
New changeset 991adca012f5e106c2d4040ce619c696ba6f9c46 by INADA Naoki in branch 'master': bpo-30048: asyncio: fix Task.cancel() was ignored. (GH-1097) https://github.com/python/cpython/commit/991adca012f5e106c2d4040ce619c696ba6f9c46 |
|||
| msg293493 - (view) | Author: Inada Naoki (methane) * ![]() |
Date: 2017-05-11 12:56 | |
New changeset 3dc7c52a9f4fb83be3e26e31e2c7cd9dc1cb41a2 by INADA Naoki in branch '3.6': bpo-30048: asyncio: fix Task.cancel() was ignored. (GH-1546) https://github.com/python/cpython/commit/3dc7c52a9f4fb83be3e26e31e2c7cd9dc1cb41a2 |
|||
| msg293524 - (view) | Author: Inada Naoki (methane) * ![]() |
Date: 2017-05-12 05:34 | |
New changeset 5e94dedcddf5e09164bf20f18a3c701eeb96c71e by INADA Naoki in branch '3.5': bpo-30048: asyncio: fix Task.cancel() was ignored. (GH-1547) https://github.com/python/cpython/commit/5e94dedcddf5e09164bf20f18a3c701eeb96c71e |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022-04-11 14:58:45 | admin | set | github: 74234 |
| 2017-05-12 05:37:59 | methane | set | status: open -> closed resolution: fixed stage: resolved |
| 2017-05-12 05:34:42 | methane | set | messages: + msg293524 |
| 2017-05-11 12:56:44 | methane | set | messages: + msg293493 |
| 2017-05-11 12:37:18 | methane | set | pull_requests: + pull_request1646 |
| 2017-05-11 12:24:58 | methane | set | pull_requests: + pull_request1645 |
| 2017-05-11 12:18:41 | methane | set | messages: + msg293492 |
| 2017-04-13 01:26:41 | methane | set | pull_requests: + pull_request1240 |
| 2017-04-13 01:07:37 | methane | set | messages: + msg291580 |
| 2017-04-13 00:44:56 | yselivanov | set | messages: + msg291579 |
| 2017-04-13 00:19:13 | methane | set | messages: + msg291578 |
| 2017-04-12 23:11:14 | abacabadabacaba | set | messages: + msg291577 |
| 2017-04-12 08:46:31 | methane | set | messages: + msg291531 |
| 2017-04-12 08:18:02 | methane | set | messages: + msg291528 |
| 2017-04-12 00:47:18 | yselivanov | set | assignee: yselivanov |
| 2017-04-12 00:11:24 | abacabadabacaba | create | |
