在 django 中使用 sync_to_async 时如何运行协程函数?
Posted
技术标签:
【中文标题】在 django 中使用 sync_to_async 时如何运行协程函数?【英文标题】:How to run coroutine function when use sync_to_async in django? 【发布时间】:2021-06-24 01:01:09 【问题描述】:我有 add_event
方法,在 django 中使用 sync_to_async 异步调用 _post
方法。但是当我在 Django shell 中测试该方法时,它甚至没有运行我的 async _post
函数而是返回协程对象。
这是我的方法:
@classmethod
def add_event(cls, data):
async_post_request = sync_to_async(
cls._post, thread_sensitive=True
)
response = async_post_request(
url=cls.ADD_EVENT,
data=data,
headers=cls.get_headers(),
json_response=False,
)
return response
Django shell 的屏幕截图:
【问题讨论】:
【参考方案1】:由于 async 函数返回一个协程,你必须等待它,或者使用 asyncio 执行它。由于您是从同步上下文中调用它,因此您应该使用最新选项:
import asyncio
@classmethod
def add_event(cls, data):
async_post_request = sync_to_async(
cls._post, thread_sensitive=True
)
response = asyncio.run(async_post_request(
url=cls.ADD_EVENT,
data=data,
headers=cls.get_headers(),
json_response=False,
))
return response
【讨论】:
我的 python 版本是 3.6.12 并且没有run
方法。同样在 django 文档中没有运行的东西。 docs.djangoproject.com/en/dev/topics/async/#sync-to-async
asyncio.run
在 Django 中不鼓励使用,因为它对于 IO 操作不是线程安全的。在这种情况下,您需要使用 await async_to_sync(func)(...)
。这基本上会使这个双重包装的async_to_sync(sync_to_async(func, thread_sensitive=True))(...)
完全没有意义。只需运行func(...)
- 双重包装只会降低效率。【参考方案2】:
您最好将 IO _get
函数重写为原生异步。使用异步 http 库,例如 aiohttp
。然后您可以在add_event
中使用async_to_sync(cls._get)(...)
。您当前正在将同步功能转换为异步,只是为了将其直接转换回同步,导致 Django 不必要地切换到异步状态。每次调用会花费您大约 4 毫秒的时间,而且加速没有任何好处,因为无论如何该函数仍将同步运行。
【讨论】:
以上是关于在 django 中使用 sync_to_async 时如何运行协程函数?的主要内容,如果未能解决你的问题,请参考以下文章
在 django-crispy 按钮名称中使用 django 模板变量
使用 django-import-export 在 django 迁移中的外键