[Twisted-Python] Question on deferreds

Ken Whitesell kwhitesell at adelphia.net
Wed Dec 7 00:19:18 EST 2005


Frank,

	Ok, your clarifications make things a little more difficult, but 
not impossible.

	Standard disclaimer: I'm no Twisted-guru. There may be an easier 
way to do this. I can only take this as far as my knowledge extends. 
So having said that...

There's no way to get around the fact that the calling program needs 
to be 'broken' down into two parts, 'separated' by the deferred.

In other words, to greatly simplify the situation, your flow should 
be something like:

function 1
	do stuff...
	do more stuff...
	do more stuff...
	callRemote...
	addCallback(function2)
return

function 2
	do more stuff...
	do more stuff...
	do more stuff...
end of tests.

The bottom line is that your entire program flow needs to be 
reworked around the Twisted methodology. (Or, in other words, you 
need to Twist your program. <g>)

I don't remember where I saw this first, but the best way I know to
describe this situation is to stop thinking of your program as a 
program and Twisted as a library. Twisted is the program, and your 
code is the library.

Your functions get called by the reactor because of some event. You
handle this event then return control to the reactor. The reactor 
then calls other functions as necessary.

So you perform some tests, then call remote to invoke a process on 
the server, register your callback and yield control back to the 
reactor.

When the reply is received, a different function gets control and 
you continue processing.

One way this can look, is to take your original program (section 1) 
and modify it to look more like the pseudo code below.

*** Original code, with modified class 3 ***
     class1():
         def check1(data):
             perform test
             if test failed:
                 return False
             if not class2.check2(data):
                 return False
             do_additional_stuff_1
             return True

     class2():
         def check2(data):
             perform test
             if test failed:
                 return False
             if not class3.check3(data):
                 return False
             do_additional_stuff_2
             return True

     class3():
         def check3(data):
             perform test
             if test failed:
                 return False

		*** This is where the flow breaks ***
             avatar.callRemote(check4,data).addCallback(afterCheck)

             if not class4.check4(data):
                 return False
             do_additional_stuff_3
             return True

         def afterCheck(result):
             return result

The simplest rework I can come up with for this is:

     class0():
        def check0(data):
             part1 = class1.check1(data)
		# Assuming part1 is either false or a deferred
             if part1:
                 part1.addCallback(afterCheck)
		else callLater(0, afterCheck, False)

         def afterCheck(result):
             # part 2
		# Do the stuff after check4
		# This would include the stuff that needs to be done
		# after the tests. So code from
                 # do_additional_stuff_x
		# can be called from here.
		finalResults = class1.do_additional_stuff_1(data)
             return finalResult

     class1():
         def check1(data):
             perform test
             if test failed:
                 return False
             if not class2.check2(data):
                 return False
		# Note, we can't get here so this code can go
             # return True

        def do_additional_stuff_1(data):
            class2.do_additional_stuff_2(data)
            more suff goes here.

     class2():
         def check2(data):
             perform test
             if test failed:
                 return False
             if not class3.check3(data):
                 return False
		# Note, we can't get here so this code can go
             # return True

        def do_additional_stuff_2(data):
            class3.do_additional_stuff_3(data)
            more suff goes here.

     class3():
         def check3(data):
             perform test
             if test failed:
                 return False

		*** This is where the flow breaks ***
             aDeferred =
avatar.callRemote(check4,data).addCallback(afterCheck)
             return aDeferred

        def do_additional_stuff_3(data):
            suff goes here.

**************************************

As you can see, it does chop things up a bit - and I'm still not 
sure that I've really captured what you're trying to do. I've just 
tried to match your existing class structure - which I believe to be 
sub-optimal in this context, given that I'm working from some very 
generic descriptions.

Specifically, I'm not sure if these "class1, class2 and class3"
definitions are truly classes, or if they're simply "organizational
usage groups". (I'm not judging one way or the other, I'm only 
working from what you've written and what assumptions I can make - 
this isn't meant to disparage your code, just that I don't feel like 
I have enough solid information to make a more accurate judgement.)

Hope this helps spark some ideas on your end.

Ken





More information about the Twisted-Python mailing list