Tornado @run_on_executor is blocking

2024/10/14 19:23:56

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.

Answer

Python (at least in the CPython implementation) has a Global Interpreter Lock which prevents multiple threads from executing Python code at the same time. In particular, anything which runs in a single Python opcode is uninterruptible unless it calls a C function which explicitly releases the GIL. A large exponentation with ** holds the GIL the whole time and thus blocks all other python threads, while a call to bcrypt() will release the GIL so other threads can continue to work.

https://en.xdnf.cn/q/69375.html

Related Q&A

Using Pandas read_csv() on an open file twice

As I was experimenting with pandas, I noticed some odd behavior of pandas.read_csv and was wondering if someone with more experience could explain what might be causing it.To start, here is my basic cl…

Disable Jedi linting for Python in Visual Studio Code

I have set my linter for Python to Pylint, but I still get error messages from Jedi. I even went to settings.json and added the line "python.linting.jediEnabled": false, but the line, though …

Bar plot with timedelta as bar width

I have a pandas dataframe with a column containing timestamps (start) and another column containing timedeltas (duration) to indicate duration.Im trying to plot a bar chart showing these durations with…

Take screenshot of second monitor with python on OSX

I am trying to make an ambient light system with Python. I have gotten pyscreenshot to save a screenshot correctly, but I cant figure out how to get it to screenshot my second monitor (if this is even …

Invoking the __call__ method of a superclass

http://code.google.com/p/python-hidden-markov/source/browse/trunk/Markov.pyContains a class HMM, which inherits from BayesianModel, which is a new-style class. Each has a __call__ method. HMMs __call__…

Efficent way to split a large text file in python [duplicate]

This question already has answers here:Sorting text file by using Python(3 answers)Closed 10 years ago.this is a previous question where to improve the time performance of a function in python i need t…

Creating a unique id in a python dataclass

I need a unique (unsigned int) id for my python data class. This is very similar to this so post, but without explicit ctors. import attr from attrs import field from itertools import count @attr.s(aut…

How to get all the models (one for each set of parameters) using GridSearchCV?

From my understanding: best_estimator_ provides the estimator with highest score; best_score_ provides the score of the selected estimator; cv_results_ may be exploited to get the scores of all estimat…

How do I perform deep equality comparisons of two lists of tuples?

I want to compare two lists of tuples:larry = [(1,a), (2, b)] moe = [(2, b), (1, a)]such that the order of the items in the list may differ. Are there library functions to do this ?>> deep_equal…

Metadata-generation-failed when trying to install pygame [duplicate]

This question already has answers here:Python pygame not installing(3 answers)Closed last year.Trying to install pygame on python 3.11 using the following command "pip install pygame" and I a…