You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何在Django中异步调用数据库后性能未获提升?

Hey there, let's break down why your async Django setup isn't delivering the QPS boost you expected, and walk through actionable fixes to get it working right.

Key Issues Holding Back Performance

1. Your aiopg Connection Pool Is Misconfigured

Looking at your code:

pool = aiopg.create_pool(dsn)

aiopg.create_pool() is an async function—assigning it directly to pool gives you a coroutine object, not an actual connection pool. Unless you've secretly awaited this elsewhere (which isn't shown in your snippet), every query would be creating a new database connection from scratch. This adds massive overhead and completely negates any async performance gains.

2. Synchronous Code Is Blocking the Event Loop

Even if your database query runs asynchronously, you're doing critical synchronous work in your async handler that blocks the single-threaded event loop:

  • Creating Model instances via a list comprehension
  • Using ModelSerializer (a fully synchronous component)

Any sync code in your async handler will pause the entire event loop until it finishes. This means your "async" setup is effectively behaving like a synchronous one—no wonder QPS hasn't changed.

3. Gunicorn + Uvloop Configuration Might Be Incorrect

Running an ASGI app with Gunicorn requires an async-compatible worker class. If you're using the default sync worker, your async code is just running in a sync context, wasting all the potential of async I/O.

4. Your Bottleneck Might Not Be Database Queries

If your original synchronous app's slowdown wasn't caused by database I/O (e.g., it was CPU-bound, or waiting on other sync services), converting just DB queries to async won't help. You need to profile to find where time is actually being spent.


Fixes to Try

A. Properly Initialize the aiopg Connection Pool

For a Channels-based ASGI app, initialize the pool during app startup to ensure it's ready for async queries:

import aiopg
from channels.routing import ProtocolTypeRouter
from django.core.asgi import get_asgi_application

dsn = 'dbname=db user=root password=password123 host=postgres-container port=5432'
pool = None

async def setup_db_pool():
    global pool
    pool = await aiopg.create_pool(dsn)

async def application(scope, receive, send):
    if scope['type'] == 'lifespan':
        while True:
            message = await receive()
            if message['type'] == 'lifespan.startup':
                await setup_db_pool()
                await send({'type': 'lifespan.startup.complete'})
            elif message['type'] == 'lifespan.shutdown':
                await pool.close()
                await send({'type': 'lifespan.shutdown.complete'})
                return
    else:
        router = ProtocolTypeRouter({
            "http": get_asgi_application(),
            # Add your other protocol routes here
        })
        await router(scope, receive, send)

B. Offload Synchronous Work to a Thread Pool

Use asyncio.to_thread() to run sync operations (like serialization and model instantiation) in a separate thread, so they don't block the event loop:

import asyncio

async def list(self, body):
    query = Model.objects.all().order_by("title")
    ares = await async_query(str(query.query))
    
    # Move sync work to a thread pool
    def process_results():
        results = [Model(**{
            "id": i[0],
            "title": i[1],
            "created": i[2].replace(tzinfo=None),
            "updated": i[3].replace(tzinfo=None)
        }) for i in ares]
        return ModelSerializer(results, many=True).data
    
    serialized_data = await asyncio.to_thread(process_results)
    return {"data": serialized_data}

C. Configure Gunicorn for Async Correctly

Use an async worker class optimized for uvloop, and tune worker counts for your workload:

gunicorn --workers=4 --worker-class=uvloop --worker-connections=1000 --bind=0.0.0.0:8000 your_project.asgi:application

If the uvloop worker doesn't play nicely, try aiohttp.GunicornWebWorker instead—it's designed specifically for ASGI apps.

D. Ditch the DIY Async ORM Hack

Manually converting ORM queries to SQL and mapping results back to models is error-prone and misses ORM optimizations. Consider using a purpose-built async ORM:

  • django-async-orm (experimental but Django-native)
  • sqlalchemy.ext.asyncio (mature, though not tightly integrated with Django)

E. Profile to Find Hidden Bottlenecks

Use tools like py-spy or the async-compatible version of django-debug-toolbar to trace where your requests are spending time. This will help you identify any unexpected sync blocks or delays you haven't considered.

内容的提问来源于stack exchange,提问作者alexyichu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:24:18