[Twisted-Python] RE: how to create state machines?

Doug Farrell dfarrell at mypublisher.com
Mon Mar 30 11:10:48 EDT 2009

Hi Andrew,
> Hi Doug:
> >This state machine initializes a system, issues an asynchronous
> command
> >that takes time to complete (say a motor move command) and then waits
> >for that command to be done before exiting. In the context of a
> >framework that is calling this state machine, the WAITCMD1 is
> >repeatedly (polling) while the asynchronous command completes. A
> system
> >can be constructed with lots of little state machines like this and
> >made to look like it is doing many things at once even though the
> >execution of the program is single threaded.
> >I understand (pretty much) the Twisted framework is like this and
> >implmenting event handlers like connectionMade(), etc., is a state
> >machine, but I'm wondering how to implement what I've outlined above
> in
> >one of Twisted's state event handlers, or inside something like
> >callLater(). For example, let's say I want to use Twisted to run a
> long
> >running daemon process that has an XMLRPC interface. That XMLRPC
> >interface is an interface to a state machine inside Twisted that
> allows
> >the caller to change state, or start new state machines, or get the
> >status of a running state machine. In that case I'm thinking I want a
> >state machine the runs continuously in the Twisted loop, structured
> like
> >the example above; co-operatively yielding back to Twisted, but
> running
> >non-stop. Something like callLater(1, stateMachine), but non-stop,
> >without even the 1 second call loop.
> If I understand your correctly, I don't think you need to implement a
> state machine to simulate concurrency with Twisted - Twisted does a
> of that for you. You can think of a Twisted application as a state
> machine - the callback being the state and the completion of the
> operation and the calling of the callback is the transition. These
> callbacks at runtime act like a thread of execution.
> def Initialize(...):
>     # do something
>     deferred = someFunctionThatReturnsADeferred()
>     deferred.addCallback(State2)
> def State2(...):
>     # do something
>     deferred = someFunctionThatReturnsADeferred()
>     deferred.addCallback(State3)
> def State3(someData):
>     # do something
>     if someData == 'State4':
>        deferred = someFunctionThatReturnsADeferred()
>        func = State4
>     elif someData == 'State5':
>        deferred = someOtherFunctionThatReturnsADeferred()
>        func = State5
>     ...
>     deferred.addCallback(func)
> if __name__ = "__main__":
>    initialize()
>    reactor.run()
> As for the Twisted loop. Well, you don't really see the Twisted loop
> since that is hidden in the reactor. Also you should distinguish
> between writing a new protocol and using an existing one.
> In the case of XMLRPC, creating the server isn't the problem.
> http://twistedmatrix.com/projects/web/documentation/howto/xmlrpc.html
> Once a XMLRPC server is created, Twisted will take responsibility for
> creating new instances (or threads if you want to see it that way). If
> you still need a state machine, then the only hiccup I can see is
> sharing  state machine (if you really need one) between XMLRPC method
> invocations.
> Cheers,
> Andrew
[Doug Farrell] Thank you very much for your detailed response, I'm kinda
getting it and am going to try out a prototype to make sure I do. As you
mention, Twisted does take care of a lot of the issues dealing with
concurrency. Having written a few threaded applications, I didn't really
want to get into starting my state machine in a thread and then having
to deal with all the cross thread data safety issues.

One thing I'm still a little confused by in your reply is how you're
getting the deferred instance. Is there a particular reason your example
does this:

deferred = someOtherFunctionThatReturnsADeferred()

rather than this:

deferred = defer.deferred()

I just want to understand if there a reason the deferred is being
created in the other function.

Again, thanks for your help and response!

More information about the Twisted-Python mailing list