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
