async def视图必须运行在ASGI服务器(如Uvicorn)上,WSGI不支持;需Django≥3.1、配置asgi.py、用sync_to_async包装ORM、httpx.AsyncClient替代requests,并避免同步中间件。

async def 视图必须跑在 ASGI 上,WSGI 下直接失效
写 async def 视图却没效果?大概率你还在用 python manage.py runserver——它默认启动的是 WSGI 服务,根本不认识 await。不是语法错,是协议层不支持。
必须换 ASGI 服务器,比如 uvicorn:
- 确认项目有
asgi.py,且内容调用的是get_asgi_application() - 启动命令换成:
uvicorn myproject.asgi:application --reload - Django 版本必须 ≥ 3.1;旧版本即使配了 ASGI 也无视
async def
漏掉任一环,async def 都会静默退化为同步执行,压测时并发数上不去,你还以为是代码写得不够“异步”。
aiohttp.AsyncClient 不能直接塞进 Django async 视图
aiohttp 是纯异步 HTTP 客户端,但它和 Django 的运行时环境不兼容:Django 的 async def 视图运行在 ASGI event loop 中,而 aiohttp.ClientSession 默认会尝试接管自己的 loop,容易引发 RuntimeError: Event loop is closed 或协程卡死。
立即学习“Python免费学习笔记(深入)”;
更稳妥的选择是 httpx.AsyncClient:
- API 风格几乎和
requests一致,迁移成本低 - 原生适配 ASGI 环境,不会抢夺或关闭 Django 的 event loop
- 支持 HTTP/2、连接池复用、超时控制等生产级特性
示例:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
async def api_proxy_view(request):
async with httpx.AsyncClient() as client:
resp = await client.get("https://api.example.com/data")
return JsonResponse({"data": resp.json()})
数据库操作必须用 sync_to_async 包装,不能直调 ORM
Django ORM 全是同步阻塞调用,User.objects.get(id=1) 返回的是模型实例,不是 Awaitable,直接 await 会报 TypeError;不加 await 则阻塞整个协程,异步等于白写。
正确做法只有这一种:
- 用
sync_to_async包装每个 ORM 调用:user = await sync_to_async(User.objects.get)(id=1) - 批量查库建议先
list()拉到内存,再用async for或普通循环处理,避免高频线程切换开销 - 自定义模型方法(如
user.get_profile())同样要包,别信“它看起来像异步”
注意:sync_to_async 底层走线程池,不是魔法——它解决的是“不让协程卡住”,但无法消除同步 IO 本身的延迟。
混合 IO 场景下,别把所有东西都 await 成串行
常见错误:查用户 → 查订单 → 调支付网关 → 发通知,四个步骤全用 await 串着写。表面是异步,实际仍是线性等待,吞吐量没提升。
真要榨干并发能力,得识别可并行环节:
- 查用户和查第三方 API(如地址解析)通常无依赖,可
asyncio.gather并发发起 - 但
sync_to_async包装的 ORM 调用不宜盲目并发——线程池有默认上限(通常 40),太多会排队,反而拖慢 - 发邮件、写日志这类低优先级操作,考虑丢进
asyncio.to_thread或 Celery,别占主协程
最容易被忽略的一点:Django 中间件、认证后端、信号处理器,只要用了同步代码,整个请求链路就可能降级。检查你是否在 process_request 里写了 requests.get 或未包装的 .save()。

















