[Twisted-Python] using a reactor in a loop

Jean-Paul Calderone exarkun at divmod.com
Thu Mar 1 16:48:41 EST 2007


On Thu, 1 Mar 2007 13:28:04 -0800, Tom Brown <brown at esteem.com> wrote:
>On Thursday 01 March 2007 09:32, Jean-Paul Calderone wrote:
>> On Thu, 1 Mar 2007 09:21:50 -0800, Tom Brown <brown at esteem.com> wrote:
>> >Hello,
>> >
>> >I am trying to use a reactor in a loop. The application will go through
>> > the loop twice then hang when trying to stop the protocol. Here's my
>> > loop:
>> >
>> > [snip]
>> >
>> >I see the 'reactor stopped' get printed out twice through the loop but I
>> > don't see 'running server' get printed out a third time. So,
>> > reactor.run() is not returning. I must be missing something or going at
>> > this completely wrong. Any suggestions?
>>
>> The simple thing you're missing is that reactors can't be restarted. :)
>> One way you can restructure your program to avoid needing to do this is to
>> put the body of your loop (minus reactor.run()) into a function which
>> returns a Deferred and to replace the call to reactor.stop() with code
>> which fires that Deferred.  You can set up callbacks on this Deferred to
>> execute the whole thing again if necessary.
>
>I read through the deferreds documentation and I'm thoroughly confused on how
>to set this up. I tried to simplify the problem with a simple function:
>
>In [60]: def foo():
>   ....:     print 'foo'
>   ....:     return Deferred()
>   ....:
>
>In [61]: d = foo()
>foo
>
>In [62]: d.addCallback(foo)
>Out[62]: <Deferred at 0xb786792cL>
>
>So, now I'm lost as to what to do from here. Any suggestions would be
>appreciated.

Something needs to call that Deferred back for anything further to happen
(though what will happen next is a TypeError, since the callback, `foo',
doesn't accept any arguments, and all Deferred callbacks need to accept at
least one argument. ;)

For example:

   >>> def foo(result):
   ...     print 'Got a result:', result
   ...
   >>> d = Deferred()
   >>> d.addCallback(foo)
   <Deferred at 0xB7D26F4CL>
   >>> d.callback("Hello, world")
   Got a result: Hello, world
   >>>                                                       

Or to set up a (terrible, infinite, actually-infinitely-recursive) loop:

   >>> def bar(lastResult=None):
   ...     print 'Previous result was:', lastResult
   ...     d = Deferred()
   ...     d.addCallback(bar)
   ...     d.callback(str(lastResult) + "bar")
   ...
   >>>

(Slightly) More realistically, you might have something like this:

   >>> class NoOp(Protocol):
   ...     def __init__(self, onConnect):
   ...             self.onConnect = onConnect
   ...     def connectionMade(self):
   ...             self.transport.loseConnection()
   ...             self.onConnect.callback(None)
   ...
   >>> def baz(ignored=None):
   ...     d = Deferred()
   ...     p = NoOp(d)
   ...     f = ClientFactory()
   ...     f.protocol = lambda: p
   ...     reactor.connectTCP(host, port, f)
   ...     d.addCallback(baz)

Which is similar to the previous example, in that it sets up a loop with
a Deferred for an asynchronous operation (connecting to a remote host),
but won't lead to infinite recursion, and might actually resemble what you
want to do. :)

Jean-Paul




More information about the Twisted-Python mailing list