
On Nov 1, 2009, at 11:17 PM, Crispin Wellington wrote:
On Fri, 2009-10-30 at 14:06 +0000, exarkun@twistedmatrix.com wrote:
It looks like your custom reactor is mainly in charge of making sure stackless.schedule() gets called at least once every 0.1 seconds. Is that right? If so, a much better approach would be to use twisted.internet.task.LoopingCall rather than implementing a custom reactor.
Is there something undesirable about that (much simpler, less fragile) approach?
I tried using LoopingCall, but it does not work. It only calls the scheduler once. I think this has to do with the fact that the stackless scheduler needs to be interwoven with the twisted reactor pump.
LoopingCall does "interweave" the function that you pass to it with the "twisted reactor pump". If you were using it correctly, it would work, as the page that you link to indicates :). What do you mean "does not work"?
There is more info about why it has to be done like this here: http://code.google.com/p/stacklessexamples/wiki/StacklessTwisted
This example, linked from that page: <http://stacklessexamples.googlecode.com/svn/trunk/examples/twisted/TwistedTi...
is roughly the same as what exarkun recommended. These examples aren't the greatest, because they tend to assume that you _always_ have Stackless code that's ready to run, and you want to run at some number of "frames per second". For simple examples this makes sense, but for a system architecture this is a limiting approach. If your stackless application wants to sit idle and wait for input, you're still going to wake up once every 1/30 second and checking to see if there's anything to do, burning CPU cycles and battery life. Also, if you want to run *faster* than the arbitrary timeout you've selected (1/30 second can be a very long time, especially if you're doing something pseudo-realtime, like audio playback) you're out of luck. Better would be to have tasklets schedule *themselves* for when they want to run. If you just want to allow the rest of the reactor a time- slice, twisted.internet.task.cooperate() will allow you to schedule a potentially arbitrary number of tasks which want to run "as often as possible" without completely swamping the reactor; you can suspend that task by returning a Deferred which only fires when more stackless stuff is actually ready to run.