Django中@sync_to_async与异步视图未并行执行问题求助
问题原因与解决方案
你的代码中两个被@sync_to_async装饰的函数串行执行,导致总耗时为7秒,核心原因是sync_to_async默认的thread_sensitive=True参数限制。
当thread_sensitive=True时,asgiref会将所有同步任务调度到同一个线程中执行(为兼容Django的线程敏感操作,比如数据库连接上下文),因此asyncio.gather无法实现并行,只能按顺序执行两个任务(2秒+5秒=7秒)。
修改方案
将@sync_to_async装饰器的thread_sensitive参数设为False,让每个同步任务在独立线程中运行,即可实现并行:
import time import asyncio from asgiref.sync import sync_to_async from django.http import HttpResponse from movies.models import Movie from stories.models import Story # 添加thread_sensitive=False参数 @sync_to_async(thread_sensitive=False) def get_movies_async(): print('prepare to get the movies...') time.sleep(2) qs = Movie.objects.all() print('got all the movies') # 添加thread_sensitive=False参数 @sync_to_async(thread_sensitive=False) def get_stories_async(): print('prepare to get the stories...') time.sleep(5) qs = Story.objects.all() print('got all the stories') async def main_view_async(request): start_time = time.time() await asyncio.gather(get_movies_async(), get_stories_async()) total = (time.time() - start_time) print("total: ", total) return HttpResponse('async!')
补充说明
2020年的教程中sync_to_async默认的thread_sensitive值为False,但后续asgiref版本(从3.0左右开始)将默认值改为True,以此优化Django数据库连接的复用和线程安全。如果你的同步任务确实需要访问Django的数据库或其他线程敏感资源,建议保持thread_sensitive=True,同时通过手动创建独立线程池的方式实现并行:
# 自定义线程池 from concurrent.futures import ThreadPoolExecutor custom_executor = ThreadPoolExecutor(max_workers=2) @sync_to_async(executor=custom_executor) def get_movies_async(): # ... 原代码不变 @sync_to_async(executor=custom_executor) def get_stories_async(): # ... 原代码不变
这种方式既保证了线程敏感操作的安全性,又能让任务并行执行。
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

