[Twisted-Python] Deferred style question.
Anthony Baxter
anthony at interlink.com.au
Fri Jan 7 02:40:27 MST 2005
Say I have an operation that takes a certain amount of time, and so I
return a deferred. While the operation is still in progress, another call is
made for the same operation.
The operation is one of those only-do-once-and-cache-the-results sort of
things. If an operation is called a second time after the first one is done,
defer.succeed(previousResult) is returned. If it's called a second time
while it's still in progress, it returns a deferred that's also triggered with
the result when the operation completes.
Should I just return the same deferred?
Initially I thought 'yes, return the same deferred', but that then relies on
the user-written callback returning the result that it was passed.
Second thought was 'no, return a new deferred', and return a new deferred and
install a callback on the original deferred that triggers a new deferred
But then if the user's callback on the original deferred raises an error, the
second deferred will never be triggered. Or it could simply return another
deferred, and delay the triggering of the second one.
So now I'm leaning towards (on the first call) making two deferreds - one for
the operation, and one to be returned to the user. Then the operation
deferred gets a callback that triggers the user's deferred. Then a second
user call can simply add a new callback to the operation deferred. Any later
calls simply add a callback to the (cached) operation deferred, they'll be
triggered immediately.
Does this make sense? Sample code to demonstrate what I mean is attached.
Anthony
--
Anthony Baxter <anthony at interlink.com.au>
It's never too late to have a happy childhood.
-------------- next part --------------
from twisted.internet import defer, reactor
# Cache of operations
_cache = {}
def longRunningOperation(value):
# Stub pointless operation - returns the value passed, after a 2s delay
opdef = defer.Deferred()
print "Operation called for", value
reactor.callLater(2, lambda :opdef.callback(value))
return opdef
def triggerUserCallback(res, deferred):
deferred.callback(res)
return res
def callOperation(value):
# Currently not in progress - start it
if not _cache.has_key(value):
opdef = longRunningOperation(value)
_cache[value] = opdef
userdef = defer.Deferred()
_cache[value].addCallback(lambda x: triggerUserCallback(x, userdef))
return userdef
def gotAResult(res):
print "I got a result!", res
def makeACall():
print "making a call for 'x'"
d = callOperation('x')
d.addCallback(gotAResult)
def startTheFun():
makeACall()
reactor.callLater(1, makeACall)
reactor.callLater(4, makeACall)
reactor.callLater(5, makeACall)
if __name__ == "__main__":
reactor.callLater(0, startTheFun)
reactor.run()
More information about the Twisted-Python
mailing list