In the case of synchronous work that can take upwards of 80ms, you'll
probably want to move that work out to a separate thread or process
pool. Then the main IOLoop thread remains unblocked and can use a
timeout to send an error response if the other thread/process doesn't
return in time.
-Ben
It's unfortunately true that threading is not as well supported in
python as in some other languages, although I have had success with
threading in tornado apps.
>
> I tried a process pool; however that failed as well... Now, the
> problem there could be that my program had errors in it and not
> necessarily Tornado or Python related. I have to consider a refactor
> of my code there.
>
> However, having a timeout at the IOLoop layer is still very useful. So
> if I simply implement a timeout handler, it should do the trick? How
> do I tell my worker process/thread to give up because IOLoop has timed
> out?
If it's a process you can simply kill it. If it's a thread things are
trickier, and depending on what it's doing there may not be a reliable
and safe way to stop it. The safest approach is to have the main
thread set a variable that the worker thread can manually check at
appropriate times (e.g. after completing a database lookup). A
java-centric discussion of the complexities of interrupting a working
thread can be found here:
http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
-Ben
I had trouble reconciling ioloop with other operations by using threads for work happening outside the ioloop interface. It could be my inexperience with threads.
But it seems that, in general, using a separate thread (or threads) can be tricky when working with data structures that the ioloop's thread of control may interact with any time. I would suggest trying to build it with the ioloop interface alone if you can, avoiding blocking calls.
If you must do blocking calls, a proper thread pool should handle it. You may want to use something (RLock comes to mind) to avoid concurrent manipulation of data structures by your thread pool vs the ioloop.
Cheers,
Chris
When I've used threading with tornado it hasn't been for concurrency
per se, but as a part of a transitional strategy for bridging legacy
synchronous django code with tornado-based async code. I had django
running in a WSGIContainer and when it needed to call out to async
code it would deadlock if the async code tried to use the same IOLoop
as the WSGIContainer. I had a second thread running its own IOLoop
and AsyncHTTPClient. To make a fetch, I'd use add_callback to
transfer control to the second thread, call the http client's fetch
method from that thread, and then use a threading.Event to let the
django code wait for the async fetch to finish. (If it was a single
fetch I could have just used a synchronous HTTPClient; actual use
often involved multiple fetches in parallel before reaching
event.set()).
-Ben