i just learn about flask and requests. i want to get the number of working threads when i post request to the server. and i want to measure the time spent of the working threads. so this is my server and my client code:
server.py
from flask import Flask
from flask import request
import time
from flaskthreads import AppContextThread
app = Flask(__name__)
@app.route("/", methods = ['GET', 'POST'])
def home():
timeout = time.time() + 10 # 5 minutes from now
while True:
test = 0
if test ==5 or time.time() > timeout:
break
return 'Hello', 200
def main():
app.run(host='0.0.0.0', threaded = True, debug = True)
if __name__ == "__main__":
main()
client.py
import os
import requests
import glob
import time
import base64
url = 'http://0.0.0.0:5000/'
def load_data():
os.chdir('./500_mb')
for image in glob.glob('*.jpg'):
with open(image, 'rb') as imageFile:
# image_s = base64.b64encode(imageFile.read())
image_s = {'file_image':open(image, 'rb')}
return image_s
def send_data():
start = time.time()
r = requests.post(url, files = load_data())
end = time.time()
print('client 1: {} ms'.format((end - start)*1000))
if __name__ == "__main__":
send_data()
how do i know the number of working threads ? i just add threaded = True
on the server. i've been searching the answer and none of them answer my question. thanks in advance !
As of Flask 1.0, flask server is multi-threaded by default. Each new request is handled in a new thread. This is a simple Flask application using default settings.
Flask will process one request per thread at the same time. If you have 2 processes with 4 threads each, that's 8 concurrent requests. Flask doesn't spawn or manage threads or processes.
Generally, Python only uses one thread to execute the set of written statements. This means that in python only one thread will be executed at a time.
With threaded=True requests are each handled in a new thread. How many threads your server can handle concurrently depends entirely on your OS and what limits it sets on the number of threads per process. The implementation uses the SocketServer.
The system was implemented in Pythons web micro-framework Flask. Threading in Python is simple. It allows you to manage concurrent threads doing work at the same time. The library is called “ threading “, you create “Thread” objects, and they run target functions for you. You can start potentially hundreds of threads that will operate in parallel.
For a multi-threaded request, it’s unclear which Request object is used at the moment. If there are some changes to be made on certain request, it can’t be guaranteed that the targeted request instance is changed, which results in contaminated data. To solve the issues of multi-threading in Flask we can use dictionary data structure, e.g.
The most common scenario is to try to access flask.g object. Application context is a thread local so you can not access it from another thread and Flask will raise an exception if you would try to. This library provides helper classes that allows you accessing the current application context from another thread.
This method of starting one thread for each task will work well unless you have a high number (many hundreds) of tasks to complete. The solution outlined above operated successfully for us, with users to our web application requiring, on average, 9-11 threads per request.
First of all, the usual disclaimer: This is pretty much irrelevant because you would be able to specify this when you actually move to a deployment server.
However, I was curious myself, so I decided to trace this back.
The starting point is in app.run()
so let's look at what that does:
def run_command(
info, host, port, reload, debugger, eager_loading, with_threads, cert, extra_files
):
...
from werkzeug.serving import run_simple
run_simple(
host,
port,
app,
use_reloader=reload,
use_debugger=debugger,
threaded=with_threads,
ssl_context=cert,
extra_files=extra_files,
)
So, next port-of-call is werkzeug.serving
with run_simple
.
From here, you'll be buffeted about the module:
make_server
make_server
launches ThreadedWSGIServer
socketserver.ThreadingMixIn
as an argument.Head over to socketserver
. We can see from the source code the following:
class ThreadingMixIn:
"""Mix-in class to handle each request in a new thread."""
...
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
if not t.daemon and self.block_on_close:
if self._threads is None:
self._threads = []
self._threads.append(t)
t.start()
So, the answer is that it launches a new thread on each request. If nothing else, it's an interesting exercise in tracing code paths.
Edit in Sept 2021: I originally made the mistake of not getting permalinks from git, so different parts of the answer went out of sync with the code paths I was trying to show. I've since corrected that to try be more stable with permalinks but, with several libraries involved, do note that things could change at any time. I think the general principle will hold for a while, though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With