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

Andrew Francis andrewfr_ice at yahoo.com
Thu Mar 26 22:48:48 MDT 2009


Hi Doug:

>Message: 1
>Date: Thu, 26 Mar 2009 14:26:17 -0400
>From: "Doug Farrell" <dfarrell at mypublisher.com>
>Subject: [Twisted-Python] how to create state machines?
>To: <twisted-python at twistedmatrix.com>
>Message-ID:
    <318F79422ADC5041A93343721F84474D01A8BB43 at exchange.mypublisher.local>
>Content-Type: text/plain; charset="us-ascii"

>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 executed
>repeatedly (polling) while the asynchronous command completes. A system
>can be constructed with lots of little state machines like this and be
>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 lot 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









      




More information about the Twisted-Python mailing list