Django服务器阻塞优化:仅异步化外部请求函数可行吗?
解决方案解析
你的问题核心是同步视图里的阻塞式外部请求占满了有限的进程,导致服务器无法处理其他请求。下面是具体的解决思路和实现方式:
为什么会阻塞
同步Django视图中,每个请求会占用一个进程/线程。当你用requests这类同步HTTP库调用外部耗时服务时,进程会一直处于“等待响应”的状态,没法释放出来处理其他请求。4个进程全被占满后,新请求自然就被阻塞了。
不需要改造整个视图
你只需要把调用外部服务器的逻辑改成异步非阻塞的,其他业务逻辑如果是同步的,可以保留或简单包装后继续使用。
推荐方案:Django异步视图 + 异步HTTP客户端
- 把视图定义为
async def(Django 3.1+支持),使用异步HTTP客户端(比如aiohttp)替代同步的requests去调用外部服务器。这样在等待外部响应时,事件循环会自动切换去处理其他请求,不会占用进程资源。 - 示例代码:
import aiohttp from django.http import JsonResponse import asyncio async def long_running_view(request): # 同步业务逻辑用asyncio.to_thread包装,避免阻塞事件循环 # sync_result = await asyncio.to_thread(your_sync_business_func) # 异步调用外部服务器 async with aiohttp.ClientSession() as session: async with session.get("https://external-server.com/calculate") as resp: external_data = await resp.json() return JsonResponse({"result": external_data}) - 注意:需要把Django部署在ASGI服务器上(比如Daphne、Uvicorn),WSGI服务器无法充分发挥异步视图的优势,甚至可能出现兼容问题。
备选方案:异步任务队列(适合无需实时返回结果的场景)
如果业务允许先给用户返回“处理中”的响应,后续再通知结果,可以用Celery这类任务队列把外部请求放到后台执行:
- 视图接收请求后,立即提交异步任务,返回
{"status": "processing", "task_id": "xxx"} - 用户通过轮询或WebSocket获取任务完成后的结果
- 这种方式不需要改造视图为异步,但需要额外维护任务队列服务
关键注意事项
- 异步视图里绝对不能调用同步的阻塞IO操作(比如
requests、同步ORM操作),否则会阻塞整个事件循环,和原来的问题一样。 - 同步ORM操作可以用
asyncio.to_thread()包装,或者升级到Django 3.2+使用异步ORM API。
内容的提问来源于stack exchange,提问作者Jakub Swistak
相关产品推荐
相关产品推荐

