I would like to ask how tornado.concurrent.run_on_executor (later just run_on_executor
) works, because
I probably do not understand how to run synchronous task to not block the main IOLoop.
All the examples using run_on_executor
, which I found, are using just time
to block the loop.
With time
module it works fine, but when I try some time intesive calculations, using run_on_executor
, the task blocks the IOLoop.
I am able to see that the app uses multiple threads, but it is still blocking.
I want to use run_on_executor
for hashing passwords using bcrypt
, but replaced it with this calculation to gain some extra time for testing.
Here I have small app, to demonstrate my confusion.
from tornado.options import define, options
import tornado.web
import tornado.httpserver
from tornado import gen
from tornado.concurrent import run_on_executor
import tornado.httpclient
import tornado.escape
import time
import concurrent.futures
import urllibexecutor = concurrent.futures.ThreadPoolExecutor(20)
define("port", default=8888, help="run on the given port", type=int)# Should not be blocking ?
class ExpHandler(tornado.web.RequestHandler):_thread_pool = executor@gen.coroutinedef get(self, num):i = int(num)result = yield self.exp(2, i)self.write(str(result))self.finish()@run_on_executor(executor="_thread_pool")def exp(self, x, y):result = x ** yreturn(result)class NonblockingHandler(tornado.web.RequestHandler):@gen.coroutinedef get(self):http_client = tornado.httpclient.AsyncHTTPClient()try:response = yield http_client.fetch("http://www.google.com/")self.write(response.body)except tornado.httpclient.HTTPError as e:self.write(("Error: " + str(e)))finally:http_client.close()self.finish()class SleepHandler(tornado.web.RequestHandler):_thread_pool = executor@gen.coroutinedef get(self, sec):sec = float(sec)start = time.time()res = yield self.sleep(sec)self.write("Sleeped for {} s".format((time.time() - start)))self.finish()@run_on_executor(executor="_thread_pool")def sleep(self, sec):time.sleep(sec)return(sec)class Application(tornado.web.Application):def __init__(self):handlers = [(r'/exp/(?P<num>[^\/]+)?', ExpHandler),(r'/nonblocking/?', NonblockingHandler),(r'/sleep/(?P<sec>[^\/]+)?',SleepHandler)]settings = dict(debug=True,logging="debug")tornado.web.Application.__init__(self, handlers, **settings)def main():tornado.options.parse_command_line()http_server = tornado.httpserver.HTTPServer(Application())http_server.listen(options.port)io_loop = tornado.ioloop.IOLoop.instance()io_loop.start()if __name__ == "__main__":main()
I would be very grateful for any explanation why ExpHandler
, running in executor
is blocking the loop.