[PEAK] StopIteration: Unexpected reactor exit
John Landahl
john at landahl.org
Thu Mar 25 22:59:52 EST 2004
On Thu, 25 Mar 2004 19:35:56 -0500, Phillip J. Eby <pje at telecommunity.com>
wrote:
> Only because you're using Twisted for both levels of event loop. PEAK
> allows you to have as many event loops as you like, but Twisted supports
> only one.
By this do you mean that there can be only one EventLoop instance per
application (which is the case in my app; it uses
"binding.Obtain(events.IEventLoop)"), or one active call to that
instance's runUntil()?
Some further information gathering has revealed that the reactor does not
get stopped until the Task in question next tries to yield. All interim
EventLoop.runUntil() invocations cause no problems. In fact, if I change
the yields in the Task to eventLoop.runUntil() calls, the problem does not
occur.
So to be a little more specific:
Task A
Creates a new Task B
Runs a method on object C (func1)
calls func2 (indirectly)
calls reactor.spawnProcess(), waits for completion with
runUntil()
calls a remote PB method, waits for completion with runUntil()
returns data
data is used to setup another spawnProcess()
yields on a deferred returned by C
processes data from the deferred
reports results via a PB call
Immediately after this yield, the runUntil() called by
EventDriven.mainLoop raises StopIteration. Using runUntil() here instead
of yield does not cause the StopIteration. Could there be something in
the Task class that causes B to end prematurely?
FWIW, the Twisted reactor's mainloop ends directly after the return on
line 462 of peak.events.event_threads.py, followed by the early demise of
EventDriven.mainLoop.eventLoop.runUntil(). Not knowing what calls
Task.step(), I'm not sure how to trace what happens between the return and
the end of the reactor's mainloop.
> You'll have to make the synchronous functions asynchronous then. What
> you do is take all the 100% synchronous parts (i.e. parts that *don't*
> call any asynchronous code), and farm them out to threads using
> reactor.deferToThread. You'll then be left with a 100% asynchronous
> task.
I don't know if it's possible to refactor it this way since the data func2
returns to its caller is dependent on the two Twisted deferreds. One
possibility might be to have these run in the main thread through
callFromThread(), but that might be difficult in this scenario. I'll look
into this option further.
More information about the PEAK
mailing list