Django 4异步查询为何未比同步查询提升性能?
我正在开展一项测试,评估升级至Django 4并将部分查询集改为异步的价值。为了测试性能,我编写了同步与异步两类视图,但在数据库交互环节未发现性能提升。我特意编写了两个低效视图来测试数据库压力:
同步视图
def some_validation(post): """Check that number of tags > 5""" return post.tags.count() > 5 @api_view(["GET"]) def posts_with_tags(request): start_time = time.monotonic() posts = [] for post in Post.objects.all(): tags = [] for tag in post.tags.all(): tags.append(tag.name) post_data = { "id": post.id, "title": post.title, "content": post.content, "tags": tags, "validation_passed": some_validation(post), } posts.append(post_data) end_time = time.monotonic() time_elapsed = end_time - start_time return Response( { "posts": posts, "time_elapsed": time_elapsed, "num_queries": len(connection.queries), } )
异步视图
async def some_validation_async(post): """Check that number of tags > 5""" return await post.tags.acount() > 5 @api_view(["GET"]) async def posts_with_tags_async(request): start_time = time.monotonic() post_data = [] async for post in Post.objects.all(): post_tags = [] async for tag in post.tags.all(): post_tags.append(tag.name) validation_res = await some_validation_async(post) post_data.append( { "id": post.id, "title": post.title, "content": post.content, "tags": post_tags, "validation_passed": validation_res, } ) end_time = time.monotonic() time_elapsed = end_time - start_time return Response( { "posts": post_data, "time_elapsed": time_elapsed, "num_queries": len(connection.queries), } )
类似地,我还创建了用于写入和删除数据的视图,但所有异步查询集交互场景均未出现性能提升,想请教可能忽略了哪些因素?
异步代码未实现真正并行:你的异步视图采用
async for逐个遍历Post,每个Post的标签查询、验证操作都是串行执行,逻辑和同步版本本质一致。异步的核心优势是并行处理IO任务,需使用asyncio.gather()等方式同时发起多个数据库查询,比如批量获取Post后,并行加载每个Post的标签并完成验证,而非逐个处理。N+1查询问题未解决:同步和异步版本都存在严重的N+1查询:先查询所有Post(1次),再为每个Post查询标签(N次),额外还有每个Post的count查询(N次),总计1+2N次查询。异步仅将同步阻塞查询替换为异步非阻塞,但查询次数未减少,串行执行下总耗时与同步版本差异极小。应使用
aprefetch_related(异步版预加载)替代循环查询,将查询次数降至1-2次,再对比性能才有意义。数据库驱动未适配异步:需确保使用真正支持异步的数据库驱动,比如PostgreSQL用
asyncpg,MySQL用aiomysql。若仍使用同步驱动(如psycopg2),Django会在异步视图中通过线程池执行同步查询,异步的性能优势会被线程池开销抵消,甚至更慢。测试场景未覆盖高并发:异步的性能优势通常在高并发场景下才显著,单个请求的异步执行耗时与同步差异不大,甚至因异步调度开销略高。需用ab、wrk等工具模拟多并发请求,对比同步与异步视图的吞吐量(每秒处理请求数),而非单个请求耗时。
ASGI服务器配置不当:若使用WSGI服务器运行异步视图,Django会兼容处理但仍依赖线程池,无法发挥异步真正优势。需配置ASGI服务器(如Uvicorn、Daphne),确保异步代码直接运行在异步事件循环中。
IO等待占比不足:异步的优势在于减少IO等待时间,若业务逻辑中IO等待占比极低,异步调度、上下文切换的开销可能抵消甚至超过IO节省的时间。只有当单个请求包含大量IO操作(如多数据库查询、外部API调用)时,异步才能体现性能提升。
内容的提问来源于stack exchange,提问作者Salaah Amin

