简体   繁体   English

Django 是否使用一个线程来处理 WSGI 或 Gunicorn 中的多个请求?

[英]Does Django use one thread to process several requests in WSGI or Gunicorn?

As per the title, I am wondering if Django, when run via WSGI or Gunicorn, uses one thread to process several requests?根据标题,我想知道 Django 在通过 WSGI 或 Gunicorn 运行时是否使用一个线程来处理多个请求?

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.) (我认为有充分的理由,例如在我的自定义模板加载器中访问当前用户和站点。Django 模板加载器不提供这两个实体。)

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?这可能吗,或者每个请求在 WSGI 和 Gunicorn 中都有自己的本地线程?

Consider here Gunicorn as a web server.将 Gunicorn 视为 web 服务器。 It has master and workers processes.它有主进程和工作进程。 Master process selects free worker process for handling http request.主进程选择空闲的工作进程来处理 http 请求。 There are 3 type of workers:有3种类型的工人:

  • synchronous ( sync )同步(同步
  • synchronous with threads (worker shares memory for running threads)与线程同步(工作线程共享 memory 用于运行线程)
  • asynchronous ( async )异步(异步

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:每个没有线程的同步工作人员一次处理一个请求,考虑我们有 2 个请求,它们要么由 2 个不同的工作人员处理(彼此分开且相互隔离 python 进程),要么由同一个工作人员处理,但如果有,则由一名工作人员按顺序或并行处理多于一个线程要使用没有线程的同步工作者运行应用程序,请按如下方式运行:

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.在上面的示例中,每个工作人员一次可以处理 2 个请求。

With async worker we would have request concurrency: each worker (python process) would process many requests at a time but by one process.使用异步工作者,我们将拥有请求并发:每个工作者(python 进程)将一次处理许多请求,但由一个进程处理。 To run gunicorn with async workers your should properly set worker class:要使用异步工作者运行 gunicorn,您应该正确设置工作者 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.理论上,Django 使用异步实例来处理不同的请求。 That is as the request from a client comes to I/O operation, it will send the I/O request (ie look up in database) and then store the current status and let another client process its request.也就是当一个客户端的请求来到I/O操作时,它会发送I/O请求(即在数据库中查找),然后存储当前状态,让另一个客户端处理它的请求。 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.因为在 Django 中总是有一个主线程负责生产线程。

To check if Django actually runs multiple threads at one time, install and use htop on your Linux machine.要检查 Django 是否真的一次运行多个线程,请在 Linux 机器上安装并使用htop

Watch how the django-simple-history works (maybe this library can meet your demands).看看django-simple-history是如何工作的(也许这个库可以满足你的需求)。 You can use:您可以使用:

try:
    from asgiref.local import Local as LocalContext
except ImportError:
    from threading import local as LocalContext

and then the variable LocalContext() is thread safe.然后变量LocalContext()是线程安全的。

Here is an example. 是一个例子。

It is safe to use threading.local with blocking functions (that's why they called blocking after all), but better use contextvars to isolate cooperative tasks as well.threading.local阻塞函数一起使用是安全的(这就是他们称之为阻塞的原因),但最好也使用contextvars来隔离协作任务。

As far as I know, Django does not depends on multi-threading.据我所知,Django 不依赖于多线程。

Each WSGI or Gunicorn runner-thread runs only one Django instance that deals with only one request.每个 WSGI 或 Gunicorn runner-thread 只运行一个 Django 实例,它只处理一个请求。

You can check that with htop or better with lsof您可以使用htop进行检查,或者使用lsof进行检查

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM