我正在尝试按照视频教程并尝试理解 django 中的异步视图和 @sync_to_async 装饰器。
我有这个代码:
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
@sync_to_async
def get_movies_async():
print('prepare to get the movies...')
time.sleep(2)
qs = Movie.objects.all()
print('got all the movies')
@sync_to_async
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!')
但是当我从浏览器调用 main_view_async 时,仍然需要 7 秒,而不是像视频教程中那样需要 5 秒。
本教程可能已过时(2020 年)。或者也许我做错了什么?你能帮忙吗?
我的输出
prepare to get the movies...
got all the movies
prepare to get the stories...
got all the stories
total: 7.0126471519470215
教程终端输出
prepare to get the movies...
prepare to get the stories...
got all the movies
got all the stories
total: 5.0126471519470215
你是对的,它是因为教程是旧的。正如您在 Django 文档 中看到的,在 2020 年底
asgiref
发生了变化:
asgiref 3.3.0 版本更改了默认值 thread_sensitive 参数设置为 True。这是一个更安全的默认值,并且在 很多情况下与 Django 交互都是正确的值,但一定要 如果从之前的 asgiref 更新,则评估sync_to_async()的使用 版本。
这个默认的
thread_sensitive
值可以更改为False
,但是,我不知道如何使用@sync_to_async
装饰器来做到这一点,但它可以这样做:
# Change the function to a regular synchronous function
# (removed the decorator and changed the name to make it obvious it's not async)
# @sync_to_async
def get_movies():
print('prepare to get the movies...')
time.sleep(2)
qs = Movie.objects.all()
print('got all the movies')
# Do the same to this function as what was done to the above function
# @sync_to_async
def get_stories():
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()
# Create async functions from the synchronous functions
# Set the thread_sensitive to False
get_movies_async = sync_to_async(get_movies, thread_sensitive=False)
get_stories_async = sync_to_async(get_stories, thread_sensitive=False)
await asyncio.gather(get_movies_async(), get_stories_async())
total = (time.time() - start_time)
print("total: ", total)
return HttpResponse('async!')