Django开发服务器中间件sleep时长在多并发请求时倍增问题求解
问题原因
你的推测完全正确,问题根源就是Django默认的开发服务器(runserver)是单进程单线程同步模型,同一时间只能串行处理一个请求:
- 多个并发请求到达时,会先进入排队队列,等待前面的请求完全处理完成(包括你中间件里的sleep阶段)才会开始处理下一个
- 你测量的
elapsed_time是当前请求get_response方法的执行时长,但没算请求排队等待的时间,所以后续排队的请求实际总耗时会叠加前面所有请求的sleep时长,出现成倍增长的情况。
你测试得到的请求耗时表现如下:
解决方案
方案1:开启runserver多线程模式(改造成本最低)
Django 3.0及以上版本的runserver命令原生支持多线程参数,启动服务时添加--threads参数指定最大线程数即可:
python manage.py runserver --threads 10
开启后每个请求会分配到独立线程处理,sleep操作不会阻塞其他请求,即可实现每个请求总耗时约2秒的预期效果。
方案2:使用支持并发的生产级服务器
如果需要更高的并发能力,可以用Uvicorn、Gunicorn这类支持多进程/多线程的服务器替代默认runserver,以Uvicorn为例:
首先安装依赖:
pip install uvicorn
随后启动服务:
uvicorn 你的项目名.asgi:application --host 127.0.0.1 --port 8000 --workers 2 --threads 8
中间件代码优化建议
你的现有代码在接口本身响应时长超过2秒时,会出现sleep传入负数的报错,建议加边界值处理:
import time from django.utils.timezone import now from django.http import HttpRequest class SnailMiddleware: """ Middleware that throttle responses """ def __init__(self, get_response): self.get_response = get_response def __call__(self, request: HttpRequest): start = now() response = self.get_response(request) elapsed_time = (now() - start).total_seconds() # 避免传入负数导致报错 sleep_time = max(0, 2 - elapsed_time) time.sleep(sleep_time) return response
内容的提问来源于stack exchange,提问作者Milano
相关产品推荐
相关产品推荐

