Hi.

I think your proposed patch makes sense.  To be honest, I hadn't even
noticed that task cancellation was asynchronous.

One could argue that the unit tests could be fixed instead of wait_for, but
I don't think there's anything to be gained by this.  If we don't lose
performance by wrapping things nicely before returning from the wait_for
call, then we might as well just do it, IMHO.  Less headaches for the Tulip
user.

Thanks.



On 7 February 2014 15:26, Victor Stinner <[email protected]> wrote:

> 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
>



-- 
Gustavo J. A. M. Carneiro
Gambit Research LLC
"The universe is always one step beyond logic." -- Frank Herbert

Reply via email to