<html><body><br />On 05:25 pm, ellisonbg.net@gmail.com wrote:<br />&gt;The issue brought up in this thread is one that we (the IPython dev<br />&gt;team) has thought about a lot. &#160;There are really two questions about<br />&gt;having true synchronization primitives (something like d.waitFor() or<br />&gt;blockOn(d)):<br />&gt;<br />&gt;1. &#160;Can they be implemented in python/twisted in a reliable and robust way?<br /><br />The real question here doesn't involve the words "in python/twisted" :).<br /><br />&gt;2. &#160;Should you use them in your code?<br /><br />&gt;Unfortunately, the answer to (1) seems to be no - at least not without<br />&gt;completely refactoring the core of twisted to support this capability<br />&gt;from the ground level. &#160;The tempting way of doing it currently is to<br />&gt;call reactor.iterate() to spin the event loop at a particular point.<br />&gt;We have code in IPython that does this:<br />&gt;<br />&gt;http://projects.scipy.org/ipython/ipython/browser/ipython/branches/saw/ipython1/kernel/blockon.py<br />&gt;[DON'T USE THIS CODE!]<br />&gt;<br />&gt;For very simple things this code works just fine.<br /><br />I think you mean, "in some cases this code appears to work". &#160;Working "just fine" implies that it is robust and supported. &#160;This is an actively deprecated programming style and there are numerous known problems (besides the ones you've already documented here) with doing it.<br /><br />&gt;d = functionThatReturnsADeferred()<br />&gt;r = blockOn(d) &#160; &#160; &#160; &#160; &#160;# spin the reactor until d fires.<br />&gt;<br />&gt;The problem is that if you start to use blockOn in various places in<br />&gt;your code, a single call to blockOn (which calls reactor.iterate())<br />&gt;could trigger other calls to blockOn (which will attempt to call<br />&gt;reactor.iterate() again). &#160;The twisted reactor is simply not designed<br />&gt;to be doubly iterated like this - it leads to all sorts of really<br />&gt;weird problems that are _impossible_ to track down.<br /><br />These "weird" problems are the entirely predictable result of violating every assumption that code makes about its run-time environment when it is written and tested. &#160;An analogous operation would be to write C code to forcibly delete Python objects rather than go through the garbage collector because you *really know*, *just this one time*, that you want to free that memory. &#160;If you're careful to never touch that object again, you might be able to avoid a segfault, but I think most people would agree that all bets are off at that point.<br /><br />This might seem like an exaggerated problem, but I have actually seen code like that more than once written by dyed-in-the-wool C programmers who didn't "get" how Python's object model worked. &#160;It's the same with dyed-in-the-wool non-concurrent programmers approaching concurrent systems for the first time.<br /><br />&gt;This is why people are saying "it can't be done." &#160;I should mention<br />&gt;that it might be possible to implement these things in stackless.<br /><br />If you were to implement these things in stackless, you would still have to deal with the inherently problematic issue of apparently "sequential" code being run recursively when it does not expect to be. &#160;In order to prevent this, you would likely have a completely different programming model where something properly event-driven, like Twisted itself, were scheduling "user code" which was written using a different programming style.<br /><br />For certain problems such things are a good approach. &#160;For example, in AI code with extremely deeply nested ad-hoc decision trees modeled as if statements and for loops, the cost of stack ripping becomes high both conceptually and performance-wise, and it is more natural to model individual agents as individual control flows (or "cooperative threads"). &#160;This sort of code, though, would be written in a style more like Erlang, with almost no shared state at all. &#160;Part of Twisted's appeal is that it makes mutable state-sharing between disparate systems straightforward. &#160;In other words, it is a different programming model for a different set of problems that would require a different pile of infrastructure.<br /><br />It may well be possible to implement such a layer on top of Twisted, but there is a curious thing that takes place when people begin to tackle this problem. &#160;Pretty much everyone eventually comes to the realization that this isn't a good idea for their problem domain, and what they *actually* want is to wish away the difficulties associated with concurrency and pretend that they can "just block" and everything will be OK. &#160;The ones who really, really need it (like people dealing with the aforementioned AI problems) already know their requirements and quietly go ahead and implement what they need, without any hand-wringing about how hard programming with Deferreds is or how they'd really like to block on one.<br /><br />&gt;So what about (2)? &#160;Ignoring the fact that such constructs can't be<br />&gt;implemented reliably (let's imagine they could be), should you want to<br />&gt;use them? &#160;I think the answer is this:<br /><br />&gt;The design of Twisted reflects the realities of an asynchronous, event<br />&gt;driven world where things can and do go wrong when you least expect<br />&gt;it. &#160;The error handling decision tree of Deferreds are a reflection of<br />&gt;this reality. &#160;If you try to make this stuff go away (we have tried ma<br />&gt;ny times - we are slow learners and very stubborn) you will be<br />&gt;punished and there will be "weeping and gnashing of teeth." &#160;This<br />&gt;punishment will take the form of buggy code that is difficult to<br />&gt;maintain and extend.<br /><br />It sounds like we broadly agree here :).<br /><br />&gt;With all that said, I have encountered a few highly unusual cases<br />&gt;where I really did want blockOn to exist. &#160;These cases had the<br />&gt;characteristic that they couldn't be done any other way in Twisted.<br />&gt;The answer in this case is to ditch twisted and use a tool that is<br />&gt;better suited to the problem. &#160;But in my experience these cases only<br />&gt;pop up about 0.00001% of the time.<br /><br />I am very curious about your 0.00001% case. &#160;Not that I don't believe such cases exist, but in every case but one (twisted ticket #2545) the issue has actually been a documentation problem with Twisted, where it wasn't clear how to do something the "normal" way with Deferreds and such. &#160;I'd like to know if there is another such doc bug we should be filing :).<br /></body></html>