2

My code looks like this:

... # class Site(Resource)
def render_POST(self,request)
   otherclass.doAssync(request.args)
   print '1'
   return "done" #that returns the HTTP response, always the same.

...

def doAssync(self,msg):
    d = defer.Deferred()
    reactor.callLater(0,self.doStuff,d,msg)
    d.addCallback(self.sucess)

def doStuff(self,d,msg):
    # do some stuff
    time.sleep(2)  #just for example
    d.callback('ok')

def sucess(msg):
    print msg

The output:

1

ok

So far, so good, but, the HTTP response (return 'done'), only happens after the delay (time.sleep(2)). I can tell this, because the browser keeps 'loading' for 2 seconds.

What am I doing wrong?

Community
  • 1
  • 1
joaoricardo000
  • 4,764
  • 4
  • 25
  • 36
  • Found some answer: http://stackoverflow.com/questions/6759115/asynchronous-wsgi-with-twisted – joaoricardo000 Feb 16 '12 at 11:45
  • 2
    Be careful about which threads you use Twisted APIs - including Deferreds, ie d.callback - in. This version of the code uses `d.callback` in the wrong thread. This leads to all the callbacks being run in the wrong thread, which will probably break something as soon as you do more than just print the result. – Jean-Paul Calderone Feb 16 '12 at 17:12

1 Answers1

4

What you are doing wrong is running a blocking call (time.sleep(2)), while Twisted expects you to only perform non-blocking operations. Things that don't wait. Because you have that time.sleep(2) in there, Twisted can't do anything else while that function is sleeping. So it can't send any data to the browser, either.

In the case of time.sleep(2), you would replace that with another reactor.callLater call. Assuming you actually meant for the time.sleep(2) call to be some other blocking operation, how to fix it depends on the operation. If you can do the operation in a non-blocking way, do that. For many such operations (like database interaction) Twisted already comes with non-blocking alternatives. If the thing you're doing has no non-blocking interface and Twisted doesn't have an alternative to it, you may have to run the code in a separate thread (using for example twisted.internet.threads.deferToThread), although that requires your code is actually thread-safe.

Thomas Wouters
  • 130,178
  • 23
  • 148
  • 122
  • 1
    So, can he replace the `reactor.callLater(...)` with a `deferToThread(...)`? – ypercubeᵀᴹ Feb 16 '12 at 12:35
  • if you do a reactor.callInThread(global_function) and global_function has a blocking operation like read a local file and process it's content. as long as the global_function is running, the factory thread seems to be affected as responses slow down noticeably, do you know why? – Ajayi Oluwaseun Emmanuel Aug 28 '15 at 18:35