0

I have a request in which I have to have a blocking call in tornado server and I do not want the main thread to be blocked for any reason. So I thought I will run it in a different thread/process.

The stub code is like this:

import tornado.web
import tornado.gen
import time
from tornado.ioloop import IOLoop

## Run this function in different process
def blocking_get(var1):
    print("blocking function")
    time.sleep(2)
    return {"res":"some result"}

class rootHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @tornado.gen.coroutine
    def get(self, *args, **kwargs):
        print("Get called for {}".format(self))
        var1 = self.get_argument('var1', None)
        ## ************************************
        ## get values from blocking call blocking_get()
        resp_dict = getRespFromDifferentProcess()
        self.write(resp_dict)
        self.finish()

    def _call_later_something(self):
        print("_call_later_something")


class TestApp(tornado.web.Application):
    def __init__(self, test=False):
        handlers = [
            (r"/", rootHandler),
        ]
        tornado_settings = dict(
            debug=True,
            serve_traceback=True,
        )

        tornado.web.Application.__init__(self, handlers, **tornado_settings)


if __name__ == "__main__":
    PORT = 8888
    print("Tornado on port {}".format(PORT))
    http_server = TestApp()
    http_server.listen(PORT)
    IOLoop.instance().start()
  1. If I run it in different thread will the GIL of python block the main thread while it is executing the blocking thread?
  2. What is the advantage of using multi-processing over multi-threading?
  3. If I have to use multi-processing in tornado how to do that?
  4. If I want the blocking code to take the values from a queue, process them and call the function in the main thread how do I have to implement it.
aja
  • 129
  • 1
  • 11

1 Answers1

1
  1. Yes it will block main thread, but for an maximum interval of 1000 bytecode commands or 15 ms (if I remember correctly). After that interpreter will switch between threads. But interpreter is quite smart and IO operations (and C-lib calls) won't block at all, so for the interpreter if time.sleep(2) runs in a separate thread it means that it will return to the main thread for ~2 seconds and then switch back. Same for the IO: if you file.read() (or wait from a queue like it your case) from a huge file it will switch to that thread only after reading is finished.
  2. This question has been answered already.
  3. You don't need that in your case. Just move queue-reading to another thread with executor for example. That's how many async DB drivers for Tornado work.
  4. See 3.
Fine
  • 2,114
  • 1
  • 12
  • 18
  • Just to make it clear to OP, GIL switches between threads very quickly, therefore the blocking is rather unnoticeable. – xyres Apr 27 '18 at 08:06
  • Thanks for the quick response. If I am not wrong the main idea of using tornado is to stop context switching. So if I use thread the context switching will still be there? – aja Apr 27 '18 at 09:14
  • Idea of Tornado is to avoid context switching for *each request*. Event-driven (kind of) context switches between main thread and 1-10 threads is ok, but a new thread for each active websocket (and it means 1 ws for 1 client, that easily goes up to 100-500 and more simultaneously) brings too much overhead of memory for each thread and CPU time to switch between them. – Fine Apr 27 '18 at 09:48
  • Now I am clear with this context switching that its OK if switch between 10 different threads and and should not create new thread for every request. For the 2nd answer you said DB drivers so drivers like `tormysql` ? So if I use `tormysql` as DB driver do I have to use process pool executor? – aja Apr 27 '18 at 10:02
  • I'm not familiar with the tormysql, but after a quick glance on it's documentation answer is no -- this lib is adapted for tornado and requires no additional manipulations with threading. – Fine Apr 27 '18 at 10:08