Integrating Twisted with Stackless Python: A Practical Guide
This article explains how to combine Twisted's event‑driven reactor with Stackless Python's micro‑threads by setting up a reactor tasklet, creating filtering and wrapper decorators, and providing deferred_tasklet and blocking_tasklet utilities to run asynchronous code synchronously.
When you need Twisted and Stackless Python to work together, the Twisted reactor must run inside the main Stackless tasklet; otherwise the reactor loop exits if there is no network activity or pending Deferreds, which is precisely why Stackless is used.
Basic setup
import stackless
from twisted.internet import reactor, task
reactor_tasklet = None
def reactor_run():
# call stackless.schedule every 0.0001 seconds
reactor_tasklet = stackless.getcurrent()
# prevent the reactor from blocking other tasklets
schedulingTask = task.LoopingCall(stackless.schedule)
schedulingTask.start(0.0001)
reactor.run()
t = stackless.tasklet(reactor_run)
# start the scheduler and run the reactor
t.run()With this configuration the reactor runs inside a Stackless tasklet and a periodic call keeps the scheduler alive.
Generalising with decorators
To turn the simple example into a reusable solution we define two helper functions using the decorator module.
def __filter(d):
if isinstance(d, failure.Failure):
if isinstance(d.value, TaskletExit):
print "ignore taskletexit"
return None
return d
return d
def __wrapper(d, f, *args, **kwargs):
try:
rv = defer.maybeDeferred(f, *args, **kwargs)
rv.addCallback(__filter)
rv.addCallback(d.callback)
rv.addErrback(__filter)
except TaskletExit:
pass
except Exception, e:
print e, dir(e)
d.errback(e __filterremoves TaskletExit exceptions that Twisted would otherwise wrap in a Failure, preventing unwanted Deferred errors. __wrapper ensures the target function is executed via maybeDeferred so that its result is always a Deferred, then wires the Deferred through the filter and the original Deferred supplied by the caller.
Deferred‑tasklet and blocking‑tasklet decorators
reactor_tasklet = None
@decorator
def deferred_tasklet(f, *args, **kwargs):
d = defer.Deferred()
t = stackless.tasklet(__wrapper)
t(d, f, *args, **kwargs)
t.run()
return d
@decorator
def blocking_tasklet(f, *args, **kwargs):
f2 = deferred_tasklet(f)
d = f2(*args, **kwargs)
if reactor_tasklet != stackless.getcurrent() and stackless.getcurrent() != stackless.getmain():
return block_on(d)
raise RuntimeError("Cannot block in reactor task")
def block_on(d):
chan = stackless.channel()
d.addBoth(lambda x, y=chan: y.send(x))
return chan.receive() deferred_taskletcreates a Deferred, runs the target function inside a new Stackless tasklet via __wrapper, and returns the Deferred so callers can attach callbacks. blocking_tasklet builds on this by converting the Deferred into a blocking call using block_on, provided the current tasklet is not the reactor’s own tasklet. block_on sets up a Stackless channel, attaches a lambda that forwards the Deferred’s result or error to the channel, and then blocks until receive() returns, effectively turning asynchronous Twisted code into sequential, synchronous‑style code.
Conclusion
By using these decorators you can safely run Twisted code inside Stackless tasklets, filter unwanted exceptions, and optionally block on Deferred results without converting the function into a generator. This approach offers a clean bridge between Twisted’s event‑driven model and Stackless’s micro‑threading, useful for projects that need both frameworks.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
