[Twisted-Python] Returning a Deferred as a result from another Deferred

glyph at divmod.com glyph at divmod.com
Sat Oct 6 07:38:09 EDT 2007


On 06:34 am, rfugger at gmail.com wrote:
>On 10/5/07, David Reid <dreid at dreid.org> wrote:

>>deferToThread is best used for taking uncontrollably blocking APIs
>>(preferably C APIs that release GIL) and getting a Deferred back.  I
>>personally can not think of a single reason why you would ever take a
>>Deferred returning API and shuffle it off to a thread.

>See my original email for the specifics.  I receive a command on a
>connection, deferToThread for handling, which involves database
>access, and then callFromThread to send a message on another
>connection, which returns a Deferred that fires when the reply is
>received, triggering a reply to the command on the original
>connection.

I assume the briefest Python summary of your code looks like this:

def thingInThread():
    databaseResult = databaseWork()
    deferred = reactor.callFromThread(otherConnection.sendRequest,
                                      databaseResult)
    return deferred

def thingInReactor():
    return threads.deferToThread(thingInThread)

This isn't really idiomatic Twisted code, because while it is 
technically safe (thingInThread doesn't *do* anything with its Deferred) 
it is slightly misleading.  Deferreds are not thread safe, and there's 
nothing you *could* do with that Deferred in thingInThread; if you 
wanted to add a callback to it, for example, you can't.

What you actually want is something more like this:

def thingInReactor():
    deferred = threads.deferToThread(databaseWork)
    def tellOtherConnection(databaseResult):
        return otherConnection.sendRequest(databaseResult)
    deferred.addCallback(tellOtherConnection)
    return deferred

This deferred can safely have callbacks added to it and generally be 
treated normally, since it never sees a thread.  Also, now you don't 
have the problem where .callback() is being called with Deferred as an 
argument; instead, you are returning one Deferred to another, which 
results in the outer Deferred ("deferred") receiving the inner 
Deferred's result (whatever "otherConnection.sendRequest" would have 
fired with).




More information about the Twisted-Python mailing list