Django使用asgiref运行异步任务却实际同步执行的问题求解
问题核心原因
你对asgiref提供的async_to_sync工具的功能定位存在根本性误解,这是问题的根源:
async_to_sync的作用是将异步函数包装为可在同步上下文调用的同步接口,调用时会阻塞当前线程,等待内部逻辑执行完成后再返回结果,完全不具备「后台异步执行、不阻塞主流程」的能力。- 你传入
async_to_sync的CallResource本身就是同步函数,这个包装操作没有任何实际意义,相当于直接同步调用了CallResource,自然会等待它执行完才走到下一行打印Answered。
解决方案
根据你的业务场景可以选择两类实现方式:
轻量场景(任务逻辑简单、无持久化/重试需求)
直接用Python内置的threading模块启动后台线程执行任务,主流程不会被阻塞,代码修改如下:
视图代码修改
import threading from django.db import connection @csrf_exempt @api_view(('POST',)) @renderer_classes((TemplateHTMLRenderer, JSONRenderer)) def IncomingMeliNotifications(request): print('--------------------------- Received ---------------------') notificacion = json.loads(request.body) # 启动后台线程执行任务,不阻塞主流程 threading.Thread(target=CallResource, args=(notificacion,)).start() print('--------------------------- Answered ---------------------') return Response({}, template_name='assessments.html', status=status.HTTP_200_OK)
任务函数修改
在CallResource末尾主动关闭当前线程的数据库连接,避免连接泄漏:
def CallResource(notificacion): # 原有业务逻辑保留 print('--------------------------- Secondary view ---------------------') # 新增:清理线程的数据库连接 connection.close() return 'ok'
该方案修改成本极低,执行时序完全符合你的预期。
生产级场景(任务量大、需要重试/监控/调度能力)
建议使用成熟的Django异步任务队列实现,可选方案包括:
- Celery:最主流的分布式任务队列,支持大量高级特性,适合中大型项目
- Django Q:轻量原生Django集成的任务队列,配置简单
- django-rq:基于Redis的轻量任务队列,性能优异
这类工具会将任务持久化存储到中间件,消费进程独立执行任务,不会受Web服务重启影响,也自带重试、失败告警等生产必备能力。
内容的提问来源于stack exchange,提问作者Francisco Ghelfi
相关产品推荐
相关产品推荐

