[Twisted-Python] Deferred style question.
Anthony Baxter
anthony at interlink.com.au
Fri Jan 7 03:13:15 MST 2005
After I posted the previous, two obvious points occurred to me:
1. This is easy enough to modify to a generally useful 'DeferredCache'
class
2. Said class is a nice example of a decorator <wink>
So, see the attached for a DeferredCache decorator. It's not perfect,
because it currently doesn't do keyword arguments, and all arguments
to the operation must be hashable. This could be fixed, although it
would make the code a bit nastier.
--
Anthony Baxter <anthony at interlink.com.au>
It's never too late to have a happy childhood.
-------------- next part --------------
# XXX To be done:
# Caching relies on all arguments to the operation being cachable.
# Caching doesn't handle keyword arguments.
from twisted.internet import defer
class DeferredCache:
""" Wraps a call that returns a deferred in a cache. Any subsequent
calls with the same argument will wait for the first call to
finish.
"""
def __init__(self, op):
self.op = op
self.cache = {}
def cb_triggerUserCallback(self, res, deferred):
deferred.callback(res)
return res
def __call__(self, *args):
# Currently not in progress - start it
if not self.cache.has_key(args):
# XXX check it returns a deferred?
opdef = self.op(*args)
self.cache[args] = opdef
userdef = defer.Deferred()
self.cache[args].addCallback(lambda x:
self.cb_triggerUserCallback(x, userdef))
return userdef
@DeferredCache
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
# Alternatively, if you don't like decorators or are on < Python 2.4
#longRunningOperation = DeferredCache(longRunningOperation)
# Testing stuff
def gotAResult(res):
print "I got a result!", res
def makeACall():
print "making a call for 'x'"
d = longRunningOperation('x')
d.addCallback(gotAResult)
def startTheFun():
makeACall()
reactor.callLater(1, makeACall)
reactor.callLater(4, makeACall)
reactor.callLater(5, makeACall)
if __name__ == "__main__":
from twisted.internet import reactor
reactor.callLater(0, startTheFun)
reactor.run()
More information about the Twisted-Python
mailing list