在 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:在管理界面中使用 TinyMCE 4

在 django-crispy 按钮名称中使用 django 模板变量

使用 django-import-export 在 django 迁移中的外键

如何使用 Django Rest Framework 在 Django 中进行操作日志记录

如何在 Django 中使用模式?

使用 Django 注册应用程序在 Django 中处理帐户/个人资料的好地方在哪里?