<br><br><div class="gmail_quote">On Fri, Oct 26, 2012 at 12:36 PM, Guido van Rossum <span dir="ltr"><<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="HOEnZb"><div class="h5">On Fri, Oct 26, 2012 at 8:52 AM, Laurens Van Houtven <_@lvh.cc> wrote:<br>
> err, I suppose the missing bit there is that you'll probably want to:<br>
><br>
> reactor.callLater(timeout, d.cancel)<br>
><br>
> As opposed to calling d.cancel() directly. (That snippet was in<br>
> bpython-urwid with the reactor running in the background, but I doubt it'd<br>
> work well anywhere else outside of manholes :))<br>
<br>
</div></div>So I think that Yuri's original problem statement, transformed to<br>
Twisted+Deferred, might still apply, depending on how you implement<br>
it. Yuri essentially did this:<br>
<br>
def foobar():  # a task<br>
    try:<br>
        yield <blocking action><br>
    finally:<br>
        # must clean up regardless of whether action succeeded or failed:<br>
        yield <blocking cleanup><br>
<br>
He then calls this with a timeout, with the semantics that if the<br>
generator is blocked in a yield when the timeout arrives, that yield<br>
raises a Timeout exception (and at no other time is Timeout raised).<br>
The problem with this is that if the action succeeds within the<br>
timeout, but barely, there's a chance that the cleanup of a<br>
*successful* action receives the Timeout exception. Apparently this<br>
bit Yuri. I'm not sure how you'd model that using just Deferreds, but<br>
using inlineCallbacks it seems the same thing might happen. Using<br>
Deferreds, I assume there's a common pattern to implement this that<br>
doesn't have this problem. Of course, using coroutines, there is too<br>
-- spawn the cleanup as an independent task.<br clear="all"></blockquote></div><br>If you call cancel() on a Deferred that already has a result, nothing happens. So you don't get a TimeoutError if the operation has succeeded (or failed some other way). This would also be true when using inlineCallbacks, so there's no issue.<br>
<br>In general I'm not clear why this is a problem: in a single-threaded program only one thing happens at a time. Your code for triggering a timeout always has the option to check if the operation has succeeded, without worrying about race conditions.<br>