Gunicorn Django 线程

3 投票
1 回答
4097 浏览
提问于 2025-04-18 08:21

我在找关于Gunicorn和Django的进程/线程生命周期的文档时遇到了困难。

假设在process_response()这个中间件钩子里启动了一个守护线程。根据我的理解,这个线程不会阻塞HTTP响应。但是,它会阻塞它所从中启动的那个线程吗?Gunicorn会等这个线程完成后再把它合并回主线程,才让工作进程准备好处理另一个请求,还是说这个线程会被分离出去?

data_collection/tasks.py:

from celery import shared_task

@shared_task(ignore_result=True)
def add_event(event_name, event_body):
    ...
    client.add_event(event_name, event_body)

data_collection/middleware.py:

import threading
from data_collection.tasks import add_event

class DataCollectionMiddleware:
    def process_response(self, request, response):
        ...
        thread = threading.Thread(target=add_event.delay, args=("Page_Views", event_body))
        thread.setDaemon(True)
        thread.start()

更多细节:

我写了一个自定义的中间件类,用来把一些数据发送到一个外部队列(RabbitMQ),然后由celery工作者异步地取回和处理这些数据。我不想让这个网络请求的入队调用阻塞客户端的响应,所以我把这个函数(add_event.delay())放在一个“守护”线程里(参考 http://www.artfulcode.net/articles/threading-django/)。如果网络出现故障,而且重试策略的限制很长,这个线程可能会运行很久。在这种情况下,这些线程会阻塞我的Gunicorn工作进程吗?

我看过这个问题,但不确定我的线程是否会干扰“工作进程的主循环”: 在Django/Gunicorn应用中,长时间运行的(非守护)线程是否危险?

1 个回答

5

不,Gunicorn工作线程生成的线程没有什么特别之处。

一旦你创建了一个线程,它会并行执行,直到完成或者结束。Gunicorn并不知道这些从工作线程主线程生成的线程,所以它不会去等待这些线程完成。因此,工作线程主线程不会等到子线程完成。此外,线程是否是守护线程也没有影响;守护线程的意思是它不会影响进程的“存活状态”,它会一直运行,直到进程退出时自动被杀掉。

如果你想在重新使用同一个工作线程之前等待这些线程完成,你必须在WSGI应用程序(例如 django.core.handlers.wsgi.WSGIHandler.__call__())返回之前做到这一点。或者你可以为Gunicorn写一些复杂的补丁,以跟踪子线程。

简单来说,你可以通过从工作线程主线程生成长时间运行的子线程来无限制地创建线程。最好确保它们在某个时间限制内完成,使用超时机制来保证。

撰写回答