Hi Jason,

I've seen your patch now, but I really would like to find a way to convince
you do come up with a different way to achieve what you're trying to do.
Your change would suddenly add a communication channel back from the
consumer to the producer that can transmit any amount of data (through
exception attributes), compared to the single "cancelled" bit that we
currently have. Can't you create an object that is shared between consumer
and producer where the consumer can indicate the difference between soft
and hard aborts?


On Tue, May 27, 2014 at 8:03 AM, Guido van Rossum <[email protected]> wrote:

> On Mon, May 26, 2014 at 6:36 PM, Jason Tackaberry <[email protected]> wrote:
>
>>
>> On 14-05-26 06:21 PM, Guido van Rossum wrote:
>>
>> Re 1: I'm not sure I follow. Have you found specific code in Tulip that
>> suppresses logging of cancellation? If so, are you sure you are hitting
>> this code? Or do you at least have example code that appears to indicate
>> this is the case? Is it perhaps the case that what you are seeing is a
>> cancel() call being ignored because the Future/Task being cancelled is
>> already completed?
>>
>>
>> Consider this example:
>>
>>  import asyncio
>>
>> @asyncio.coroutine
>> def some_long_coroutine():
>>     print('starting long task')
>>     yield from asyncio.sleep(10)
>>     print('done long task')
>>
>>
>> @asyncio.coroutine
>> def go(task):
>>     print('Waiting for task')
>>     yield from task
>>     print('done waiting for task')
>>
>>
>> loop = asyncio.get_event_loop()
>> task = asyncio.Task(some_long_coroutine())
>> loop.call_later(1, task.cancel)
>> loop.call_soon(asyncio.async, go(task))
>> loop.run_forever()
>>
>>
>> Here the task is cancelled, which cancels the coroutine go().
>> CancelledError is raised inside of go() as you'd expect, and I can catch it
>> at the 'yield from task' point if I want.  But if I don't catch it, as in
>> this example, nothing is logged.
>>
>> This is the part I find violates the principle of least astonishment. :)
>>
>
> It just means you haven't really "got" it yet. :-)
>
>
>>  I would guess this is working by design if not by intention, because
>> Future.cancel() doesn't set Future._log_traceback and Future.__del__ only
>> looks at _log_traceback.
>>
>
> Yes. I have thought about this and I can explain it better now:
>
> A Future mediates asynchronous communication between two parties. Let's
> call them the producer and the consumer. The consumer is interested in the
> Future's result; the producer is responsible for setting the result.
>
> An exception is also a kind of result; like a regular result, it travels
> from the producer to the consumer. It is special in that we interrupt the
> consumer's regular flow and re-raise it in their context, so they can
> handle it. Debugging of programs has taught is that unhandled exceptions
> typically indicate bugs, and it helps to log them.
>
> A cancellation, however, is different. It is initiated by the *consumer*
> to indicate that it is no longer interested in the result. There are many
> common patterns where once the consumer has cancelled a Future it just
> throws it away, and whether the producer handles or ignores the
> cancellation is just a matter of resource preservation. The producer may
> get the CancelledError exception thrown into its flow (if it is a
> generator, and even then only if it yields from some other Future). The
> producer does not have to handle this exception, and by convention it can
> let it bubble out without harm (perhaps cleaning up some state on the way
> out using try/finally or with-statements).
>
> When the CancelledError bubbles all the way out of the producer, there is
> nothing left to do. The producer has cleaned up all it can (if any); the
> consumer has already indicated it is no longer interested in this
> particular Future. So there really is no compelling reason to log it.
>
> As an experiment, I added "self._log_traceback = True" to Future.cancel()
> and ran the unittests. There were 81 log messages about cancelled Futures.
> I think this speaks for itself; I wouldn't want to add extra code just to
> suppress that exception to all those perfectly fine tests.
>
>
>>
>>
>>
>>  Re 2: I suppose there are some philosophical differences between
>> cancellation Tulip and abort in Kaa. Does Kaa support Futures that aren't
>> tied to a coroutine? (The Future class in Tulip has no coroutine -- only
>> its Task subclass does.) What do you suppose should happen to a non-Task
>> Future when it gets cancelled?
>>
>>
>> You're right that Kaa doesn't have a notion of bare coroutines, and every
>> coroutine returns a Future object.   I appreciate this optimization
>> decision that went into Tulip.
>>
>> These are the rules that seem intuitive to me:
>>
>>    1. The signature looks like Future.cancel(exc=None).  If exc is
>>    passed, it must be an instance or class that subclasses CancelledError.
>>     2. If Future.result() or Future.exception() is called, it will raise
>>    the exception passed to Future.cancel().  If no exception was passed, it
>>    will raise CancelledError as today.
>>     3. If a Task is cancelled with a custom exception, that exception is
>>    raised inside the coroutine and bubbled up the call stack.
>>    4. If a Gathering Future is cancelled with a custom exception, all
>>    the child futures are cancelled with that exception.
>>
>>
>> There's a zen of Python line that could possibly apply: "If the
>> implementation is easy to explain, it may be a good idea." So if you can
>> come up with a patch that looks particularly clean and elegant you may
>> convince me.
>>
>>
>> I gave it a whirl.  Attached.  Consider it a first approximation.  I
>> didn't verify the windows bits and a proper patch would have unit tests.
>>
>> But I submit this for your consideration.  If you aren't too aghast with
>> what you see, then I'll open an issue and polish things up.
>>
>> Thanks,
>> Jason.
>>
>
> I will have a look at this later today; I ran out of time while writing up
> the reason why CancelException isn't logged.
>
> --
> --Guido van Rossum (python.org/~guido)
>



-- 
--Guido van Rossum (python.org/~guido)

Reply via email to