Django — async_to_sync 对比 asyncio.run

Django — async_to_sync vs asyncio.run

我们可以使用这两个函数来同步 运行 任何异步函数:

import asyncio
from asgiref.sync import async_to_sync

asyncio.run(asyncio.sleep(1))
async_to_sync(asyncio.sleep)(1)

有什么区别?我们可以 总是 使用 asyncio.run 而不是 async_to_sync 吗?

差异

  1. 他们有不同的目的。 async_to_sync 将可等待对象转换为同步可调用对象,asyncio.run 执行协程并 return 结果。

  2. 根据 documentation,来自 async_to_sync 的可调用函数在 子线程.

    中工作
  3. async_to_sync 不会为每个线程创建事件循环,以防您处于由 sync_to_async 和 运行ning 生成的同步代码中异步代码。它重用了一个异步代码循环。举个例子:

import asyncio
from asgiref.sync import async_to_sync, sync_to_async

async def running(n):
    return [await sync_to_async(sync)(i) for i in range(n)]

def sync(n):
    # it will create a new loop for every call
    return asyncio.run(from_sync(n))

async def from_sync(n):
    return n

print("Result:", asyncio.run(running(3)))

这个将 运行 4 个循环:1 次调用 running,3 次调用 from_sync

如果我们在 sync 中使用 async_to_sync 而不是 asyncio.run,我们将把调用 running.

的循环次数减少到 1

要查看它,您可以包装 new_event_loop 函数:

def print_deco(fn, msg):
    def inner():
        res = fn()
        print(msg, res)
        return res
    return inner
p = asyncio.get_event_loop_policy()
p.new_event_loop = print_deco(p.new_event_loop, "NEW EVENT LOOP:")

您可以在post中找到详细的解释。