把视图写成 async def,请求就并发了吗?不一定,取决于它跑在什么服务器上。这篇用真实的 uvicorn 和 gunicorn 各起一个进程,同样的视图打 20 个并发请求,看哪些组合真的并发。
uvicorn + async def 视图(asyncio.sleep) 总耗时 513 ms 单个请求最快 503 / 最慢 508 ms 全部 200: True uvicorn + 普通 def 视图(time.sleep) 总耗时 520 ms 单个请求最快 509 / 最慢 515 ms 全部 200: True gunicorn 同步 worker + async def 视图 总耗时 10072 ms 单个请求最快 504 / 最慢 10068 ms 全部 200: True gunicorn 同步 worker + 普通 def 视图 总耗时 10067 ms 单个请求最快 504 / 最慢 10063 ms 全部 200: True
ASGI 下 async 与 sync 视图都是并发的,WSGI 同步 worker 下都是排队的——所以 async def 本身不是并发的原因,ASGI 服务器才是。两个视图要「等」的方式不同:await asyncio.sleep 不占线程,time.sleep 占着线程。在 ASGI 下 sync 视图能并发,是因为 Django 给每个请求分配了单独的线程(第 112、113 篇会用线程名验证)。
视图里的「等待」是 sleep,不是真的数据库或网络调用;并发数只有 20;worker 数是 1。sync 视图在 ASGI 下并发数很大时会受线程数量限制,本篇没有测。