[Twisted-Python] Synchronization techniques
glyph at divmod.com
glyph at divmod.com
Wed Apr 4 11:43:02 MDT 2007
On 04:35 pm, daniel at keystonewood.com wrote:
>On Apr 3, 2007, at 8:42 PM, Itamar Shtull-Trauring wrote:
>>On Tue, 2007-04-03 at 17:07 -0400, Daniel Miller wrote:
>>>>twisted.internet.defer.DeferredLock and some of the related classes
>>>>are
>>>>what you ought to be using.
>>>
>>>Unfortunately that only gets me half way there. DeferredLock.acquire
>>>() returns a deferred. How do I return the result of a deferred from
>>>a PB remote_xxx() function?
>>
>>Just return the Deferred from the remote_xxx() function.
>
>Thanks, I didn't know I could return a deferred from a PB remote_xxx ()
>method. That detail doesn't seem to be documented in the Perspective
>Broker documentation, which I have read quite a few times.
The PB documentation is not too great. Perhaps this paper would be
helpful to you, if you haven't seen it:
http://www.lothar.com/tech/papers/PyCon-2003/pb-pycon/pb.html#auto7
"""
In addition, the remote method can itself return a Deferred instead
of an
actual return value. When that Deferreds fires, the data given to the
callback will be serialized and returned to the original caller.
"""
>Maybe this could be highlighted in the "Complete Example" [0] section
>of the PB usage documentation? The examples use the TwistedQuotes
>application, and the IQuoter.getQuote() method always returns a string
>(at least I couldn't find any implementations that return a deferred).
Please feel free to write some patches for the documentation, or open a
doc bug describing this issue in more detail. It's definitely an under-
documented feature of PB.
>However, that would require rewriting most if not all implementations
>of IQuoter to return deferred's and/or the code that calls
>IQuoter.getQuote(), which demonstrates the viral nature of twisted
>when used in conjunction with other libraries.
I don't think that would really be the terrible burden that you suggest,
considering the relatively small amount of tutorial documentation that
implements or calls IQuoter. One could also propose a separate
interface, IDeferredQuoter, to make the distinction clearer.
>So anyway, I rewrote my server-side library to do it the twisted way
>and return deferred's instead trying rig up some way of waiting for
>them. I still think it would be super useful to be able to pseudo-
>block on a deferred (i.e. allow the reactor to process other events
>while waiting for the deferred). It is very annoying to have to
>rewrite many layers of code when twisted is introduced into a program.
>I did find gthreadless.py, and maybe that would do it. Unfortunately
>discussion on that seems to have been dropped some time ago...
I'm afraid that the feature you want doesn't make any sense and is, in a
broad sense, impossible. There are some things like it which might be
possible - for example, http://twistedmatrix.com/trac/ticket/2545 - but
the reactor is not reentrant and in some sense could not be made
reentrant.
Consider this innocuous looking block of code:
from twisted.internet.protocol import Protocol
from make_believe import magicallyBlockOn
class MagicalProtocol(Protocol):
def dataReceived(self, data):
commands = (self.buf + data).split()
self.buf = commands[-1]
for command in commands[:-1]:
if command == 'QUIT':
self.transport.loseConnection()
return
else:
# Deferreds are hard, let's go shopping
page =
magicallyBlockOn(getPage("http://example.com/%s" %
(command,)))
self.transport.write("SIZE:"+len(page))
If you were using Deferreds to track the result of the 'getPage'
operation, you could cancel the callbacks that write to the transport in
connectionLost. However, with magical blocking, one dataReceived method
might be interleaved with another. That means that every time through
the loop, you have to check to see if the transport has already been
disconnected - the code as presented here is buggy and will spuriously
fail depending on the order of the connection being lost and the remote
page being retrieved.
In this example I've been careful to accumulate all the buffer-
management and parsing logic at the top of the method, before any
potential re-entrancy can happen, but other code (most everything in
Twisted's existing protocol implementations, not to mention just about
all application code) would not be so lucky.
It might be quite feasible to implement a microthreaded runtime
environment that lived on _top_ of Twisted and explicitly accounted for
issues like these, but that would not really be substantially different
than 2.5+inlineCallbacks.
>For the record, I've included updated versions of the previously
>posted code below. I'd be happy if someone pointed out if I'm doing
>anything wrong (with respect to twisted) in this code.
Nothing immediately jumps out at me. I've had to write similar code in
the past, though, and when I've had to do that, an explicit state
machine for the state of the subprocess (or whatever asynchronous
resource must be acquired) has been easier to deal with than a lock-
oriented approach to it.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20070404/a5152cc2/attachment.html>
More information about the Twisted-Python
mailing list