Hi,
I have a complex issue in Trollius, and I just realized that Tulip has
the same behaviour (but the consequence are less important). Do you
think that the issue should be fixed in Tulip too? I mean apply this
patch to Tulip:
https://bitbucket.org/enovance/trollius/commits/e8e82dc
Ok, now let's see the whole story.
* * *
The following script displays "Task cancelled on timeout? False":
---
import asyncio
@asyncio.coroutine
def coro():
task = asyncio.async(asyncio.wait_for(asyncio.sleep(1.0), 0.1))
try:
yield from task
except asyncio.TimeoutError:
print("Task cancelled on timeout? %s" % task.cancelled())
loop = asyncio.get_event_loop()
loop.run_until_complete(coro())
---
The problem is that wait_for() calls fut.cancel(), but Task.cancel()
cancels itself asynchronously if the task is waiting for a Future
object. There is a pending call to Task._wakeup() which will be
executed later.
I found this surprising behaviour while trying to fix an issue in
Trollius: test_wait_for() fails with Trollius.
I modified wait_for() in Trollius to wait until the task is really
cancelled, changset:
https://bitbucket.org/enovance/trollius/commits/e8e82dc
* * *
In Trollius, the situation is worse than Tulip because there are more
links between futures and tasks. See this example:
---
@asyncio.coroutine
def task2():
yield [from] asyncio.sleep(1.0)
@asyncio.coroutine
def task1():
yield [from] task2()
---
With Tulip, task1() waits for sleep internal future:
task1 => sleep future
With Trollius, task1() waits for task2() which itself waits for sleep
which waits for sleep internal future:
task1 => task2 => sleep => sleep future
Cancelling task1 is first propagated synchronously to the left (to
child futures), and then come back asynchronously to the parents (to
task1).
In Tulip, test_wait_for() test pass because there is just one pending
call to cancel task1. In Trollius, it takes more roundtips of event
loop, because each cancellation requires one loop iteration.
Victor