On 7 February 2014 15:51, Guido van Rossum <[email protected]> wrote:

> But what if the task catches the exception and ignores it? That is
> legitimate behavior. The task should be allowed to continue in the
> background if it wishes.
>

Oh, good point.  For instance, if there is a shield() task, it will just
ignore the cancellation.  If wait_for() waits for it, it will wait
indefinitely.


>
>
> On Fri, Feb 7, 2014 at 7:26 AM, 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
>>
>
>
>
> --
> --Guido van Rossum (python.org/~guido)
>



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

Reply via email to