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

如何在Django 3中使用内置async、asyncio与Uvicorn实现模型异步计算及存储?

用Python async/asyncio + Uvicorn改造Django 3的异步模型操作

首先得明确:Django 3.x的ORM完全不支持异步操作,这是你之前改造碰壁的核心原因之一——直接在异步函数里调用同步ORM方法会阻塞事件循环,甚至引发错误。下面是用Python内置工具实现需求的可行方案,核心思路是「异步调度+线程池执行同步ORM操作」:

步骤1:改造信号处理流程

Django 3不支持异步信号处理器,所以我们需要保留一个同步的信号回调函数,在里面启动异步任务;真正的耗时逻辑放到异步函数中,同步ORM操作则委托给线程池执行。

修改后的models.py代码

import asyncio
import logging
from concurrent.futures import ThreadPoolExecutor
from django.db import transaction
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Case, ModelImages

# 初始化线程池,用于执行同步ORM操作,大小根据服务器配置调整
executor = ThreadPoolExecutor(max_workers=4)
logger = logging.getLogger(__name__)

def get_slices(instance):
    # 你的原有切片生成逻辑
    # 如果这部分是CPU密集型,建议也放到线程池执行(见下文说明)
    return images_array_list

# 同步ORM操作的封装函数,必须在线程池中执行
def _sync_save_model_image(instance, img_name):
    with transaction.atomic():
        case_img = ModelImages(case=instance, img=img_name)
        case_img.save()

# 异步保存单张图片的函数
async def async_save_model_image(instance, img_name):
    loop = asyncio.get_event_loop()
    try:
        # 把同步保存操作提交给线程池执行
        await loop.run_in_executor(executor, _sync_save_model_image, instance, img_name)
    except Exception as e:
        logger.error(f"Failed to save image {img_name}: {str(e)}")

# 异步处理3D图片的核心函数
async def process_3d_image_async(instance):
    # 处理切片生成:
    # 如果get_slices是IO密集型(比如读文件/调用外部API),建议改写成async函数并await
    # 如果是CPU密集型,同样用线程池执行:
    # loop = asyncio.get_event_loop()
    # imgs = await loop.run_in_executor(executor, get_slices, instance)
    imgs = get_slices(instance)

    # 批量异步保存所有图片
    save_tasks = [async_save_model_image(instance, img) for img in imgs]
    await asyncio.gather(*save_tasks)

# 同步信号回调,负责启动异步任务
@receiver(post_save, sender=Case)
def process_3d_image(sender, instance, created, **kwargs):
    if created:
        # 启动异步任务,依赖活跃的asyncio事件循环(Uvicorn提供)
        asyncio.create_task(process_3d_image_async(instance))

步骤2:用Uvicorn作为ASGI服务器运行项目

Django默认的runserver是WSGI服务器,没有活跃的asyncio事件循环,asyncio.create_task会报错。必须用Uvicorn启动项目:

uvicorn your_project_name.asgi:application --reload

关键注意事项

  1. ORM操作必须放线程池:Django 3.x的ORM是同步实现,不能在异步协程中直接调用,否则会阻塞整个事件循环,甚至触发数据库连接错误。
  2. 根据任务类型优化get_slices:
    • 如果是IO密集型(比如读取本地3D文件、调用第三方图片处理API),建议用aiofiles等异步库重写成async函数,避免阻塞。
    • 如果是CPU密集型(比如大量图像计算),一定要放到线程池(或进程池)执行,否则会占用事件循环线程,导致整个服务响应变慢。
  3. 错误处理与日志:异步任务的异常不会自动抛出到主线程,所以一定要在异步函数中添加try-except块,用日志记录错误,方便排查问题。
  4. 线程池大小调整:根据服务器的CPU核心数和并发量调整max_workers,避免创建过多线程导致资源耗尽。

为什么Celery/Trio可能没生效?

  • Celery需要正确配置消息队列(比如Redis/RabbitMQ),如果配置不当或者任务没有被正确消费,就会看起来没效果。
  • Trio是独立的异步框架,和Django的WSGI环境兼容性差,必须配合ASGI服务器才能正常运行,而且同样需要处理ORM的同步问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 11:27:57