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

如何异步运行Django API?解决单用户请求阻塞问题

解决Django长耗时API阻塞同一用户其他请求的方案

问题根源

这种情况的核心原因是Django默认的数据库会话存储机制:当处理用户请求时,Django会对该用户的会话数据库行加排他锁,直到请求处理完成才释放。同一用户的后续请求会因为等待这个锁而被阻塞,不同用户的会话行互不影响,所以其他用户可以正常请求。

以下是无需Celery/Redis异步任务框架的解决办法:


1. 更换会话存储后端

放弃数据库会话,改用缓存类会话存储,这类存储不会对用户会话加排他锁,能支持同一用户的并发请求。

配置示例(使用Memcached缓存)

在settings.py中修改:

# 配置缓存后端
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

# 切换会话引擎到缓存
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

如果用Redis作为缓存(仅做会话存储,不用于Celery任务),可以用django-redis包:

# settings.py
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"

2. 手动释放会话锁(针对数据库会话)

如果不想更换会话后端,可以在长耗时任务执行前手动保存会话以释放锁,避免阻塞后续请求。

代码修改示例

class CreateOrderAPIView(APIView):
    def post(self, request):
        # 提前保存会话,释放数据库锁
        request.session.save()
        
        # 执行长耗时的第三方服务调用
        # 比如:response = requests.post("https://third-party-service.com/api", ...)
        
        # 如果后续修改了会话,需要再次保存
        # request.session['order_id'] = order.id
        # request.session.save()
        
        return Response(order_data, status=201)

注意:如果长耗时任务中需要修改会话,要确保任务结束后重新保存会话,否则会话变更会丢失。


3. 使用异步视图(Django 3.1+)

将视图改为异步模式,用异步IO处理长耗时的第三方调用,避免阻塞请求线程,同一用户的其他请求可以在空闲线程中处理。

代码示例(使用aiohttp异步调用第三方服务)

首先安装aiohttp:

pip install aiohttp

然后修改视图:

import aiohttp
from rest_framework.views import APIView
from rest_framework.response import Response

class CreateOrderAPIView(APIView):
    async def post(self, request):
        # 异步调用第三方服务
        async with aiohttp.ClientSession() as session:
            async with session.post("https://third-party-service.com/api", json=request.data) as resp:
                third_party_data = await resp.json()
        
        # 创建订单逻辑
        order_data = {"id": 123, "status": "created", **third_party_data}
        
        return Response(order_data, status=201)

如果第三方服务没有异步SDK,可以用asyncio.to_thread包装同步调用,避免阻塞事件循环:

import asyncio
import requests

async def post(self, request):
    # 用线程池运行同步请求
    third_party_response = await asyncio.to_thread(
        requests.post,
        "https://third-party-service.com/api",
        json=request.data
    )
    third_party_data = third_party_response.json()
    
    # 创建订单逻辑
    return Response(order_data, status=201)

4. 调整会话保存策略

如果你的长耗时请求没有修改用户会话,可以在settings.py中关闭每次请求都保存会话的行为,这样Django不会对会话加锁:

# settings.py
SESSION_SAVE_EVERY_REQUEST = False

限制:如果请求过程中修改了会话(比如设置request.session['key'] = value),这个方法无效,因为Django仍会加锁保存会话。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 11:03:25