As per the title, I am wondering if Django, when run via WSGI or Gunicorn, uses one thread to process several requests?
I know it is a bad practice to access the request from places not meant to be accessed from, but I still want to do it. (for good reasons in my opinion, such as accessing the current user and site in my custom template loader. Django template loader doesn't offer these two entities.)
Now I managed to get access to the user, etc. from everywhere using the following bit of code:
import threading
_thread_locals = threading.local()
def get_current_request():
return getattr(_thread_locals, "request", None)
class RequestThreadMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
_thread_locals.request = request
response = self.get_response(request)
return response
My question/concern is: is it guaranteed that requests/users don't get mixed up in production? I am concerned the second user, for instance, gets identified as the first user because the thread is being used for my than one request. Or, the request gets overwritten by another request while the original request hasn't finished yet. Is that possible, or every request has its own local thread in WSGI and Gunicorn?
Consider here Gunicorn as a web server. It has master and workers processes. Master process selects free worker process for handling http request. There are 3 type of workers:
Each sync worker without threads handles single request at a time, consider we are having 2 requests they either would be handled by 2 different workers (separate and isolated from each other python processes) or same worker but sequentially or parallely by one worker if it has more then one thread To run an app with a sync workers without threads run it as follows:
gunicorn --workers=3 main:app
To run an app with a sync workers and with a threads:
gunicorn --workers=3 --threads=2 --worker-class=gthread main:app
In above example each of the worker could handle 2 requests at a time.
With async worker we would have request concurrency: each worker (python process) would process many requests at a time but by one process. To run gunicorn with async workers your should properly set worker class:
gunicorn --worker-class=gevent --worker-connections=1000 --workers=3 main:app
It could be fully quarantied that request don't get mixed if you choose sync workers without threads and it seems that async too, for sync workers with threads your should to implement thread synchronization where multiple threads could write simultaneously.
In theory, Django uses asynchronous instances to process different requests. That is as the request from a client comes to I/O operation, it will send the I/O request (i.e. look up in database) and then store the current status and let another client process its request. Thus, you need not worry "thread safe" or "thread data safe" issue. Because there is always a master thread in Django that takes care of production threads.
To check if Django actually runs multiple threads at one time, install and use htop
on your Linux machine.
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