[Twisted-Python] How to force synchronous behavior
James Y Knight
foom at fuhm.net
Sun Oct 30 19:58:51 MST 2005
Given that there has already been a long thread about how one should
not do this, which I completely agree with, I'll not repeat it. Note
that I do not recommend this solution to the OP, but rather post this
just to appease to the people complaining about how the only answer
given is "don't do that". "Don't do that" is the correct answer given
the information so far available, but, here's a different non-answer,
with code.
On Oct 28, 2005, at 5:40 PM, Pedro Sanchez wrote:
> def mySyncFunc()
> x = 0
> def done(data):
> global x
> x = data
>
> d = someCalculation()
> d.addCallback(done)
> <something here to hold until "done" is really done>
> return x
>
> print mySyncFunc()
>
The above code cannot work because for "done" to become done, the
twisted event loop must get a chance to run. For the event loop to
get a chance to run, you must return from that function. Basically,
how can you "block" waiting for an async event, while letting the
twisted event loop continue running? There is an answer: run your
code in a separate thread. However, that doesn't work either, because
the OP wants to use twisted APIs like ADBAPI or networking in
someCalculation. So there really is no way to do literally what's
asked in a working way. But, you can get something "like" the above
by splitting your code into synch-like-code to be run in a separate
thread, and async-twisted-using-code to be run in the twisted reactor
thread.
Here's a little example. Please note, again, that I do not recommend
doing this except in circumstances where you absolutely must.
import Queue
from twisted.internet import reactor, defer
from twisted.python import failure
def callInReactor(__f, *__a, **__kw):
# Called in other thread
queue = Queue.Queue()
reactor.callFromThread(_calledFromThread, queue, __f, __a, __kw)
result = queue.get()
if isinstance(result, failure.Failure):
result.raiseException()
return result
def _calledFromThread(queue, f, a, kw):
# Called in reactor thread
result = defer.maybeDeferred(f, *a, **kw)
result.addBoth(queue.put)
def someCalculation():
# A demo "calculation"
d = defer.Deferred()
reactor.callLater(4, d.callback, 'hi')
return d
x = 0
def myAsyncFunctionInTwistedThread():
def done(data):
global x
x = data
d = someCalculation()
d.addCallback(done)
return d
def mySyncFuncInAnotherThread():
# NOTE: in this other thread you cannot call any twisted APIs
besides reactor.callFromThread
# and a very few select others.
callInReactor(myAsyncFunctionInTwistedThread)
# callInReactor blocks until the deferred returned by
myAsyncFunctionInTwistedThread fires
print x
# Start up a thread to call your blocking function in
reactor.callInThread(mySyncFuncInAnotherThread)
# Run the reactor
reactor.run()
James
More information about the Twisted-Python
mailing list