一、asgiref.sync 是什么?

asgiref.sync 是 ASGI(Asynchronous Server Gateway Interface)参考实现库 asgiref 中的核心子模块,主要用于安全地桥接同步代码与异步代码

📌 一句话总结
它让你在异步环境中调用同步函数(如 Django ORM),或在同步环境中调用异步函数(如管理命令中调用 async API),而不会破坏事件循环或导致线程混乱。

该模块随 Django 3.0+(2019 年底) 成为主流,并成为现代 Python 异步生态的关键粘合剂


二、核心组件与 API

asgiref.sync 主要提供两个装饰器/转换器类:

组件 类型 作用
sync_to_async 装饰器 / 可调用对象 将同步函数 → 异步函数
async_to_sync 装饰器 / 可调用对象 将异步函数 → 同步函数

此外,还包含内部工具类(通常用户无需直接使用):

  • AsyncToSync
  • SyncToAsync

三、详细使用方式与场景

1. sync_to_async —— 同步 → 异步

典型场景
  • 在 Django 异步视图 中调用 ORM、缓存、文件操作(这些是同步的)
  • 在 FastAPI/Quart 异步路由 中调用阻塞库(如 requestsPillow
基本用法(装饰器)
from asgiref.sync import sync_to_async

@sync_to_async
def get_user_count():
    # Django ORM 是同步的!
    return User.objects.count()

async def my_view(request):
    count = await get_user_count()  # 安全调用
    return JsonResponse({"count": count})
高级用法(带参数)
# thread_sensitive=True(默认):确保同一请求的多次调用在同一线程
@sync_to_async(thread_sensitive=True)
def database_operation(user_id):
    return Profile.objects.get(user_id=user_id).data

# thread_sensitive=False:用于无状态计算(如加密、图像处理)
@sync_to_async(thread_sensitive=False)
def cpu_bound_task(data):
    return heavy_computation(data)
参数说明
参数 默认值 说明
thread_sensitive True 关键! 若为 True,所有调用共享同一线程局部状态(对 Django ORM 至关重要)
executor None 自定义线程池(默认使用专用线程池)

💡 为什么 thread_sensitive=True 如此重要?
Django 的数据库连接、中间件状态等都存储在 线程局部变量(thread-local) 中。
如果两次 ORM 调用在不同线程,会导致连接混乱、事务错乱、甚至数据污染!


2. async_to_sync —— 异步 → 同步

典型场景
  • Django 管理命令manage.py 脚本)中调用异步服务
  • Flask/Django 同步视图 中集成 async 库(如 aiohttp
  • 测试脚本 或 Jupyter Notebook 中调用异步函数
基本用法
from asgiref.sync import async_to_sync
import httpx

async def fetch_data(url):
    async with httpx.AsyncClient() as client:
        resp = await client.get(url)
        return resp.json()

# 转换为同步函数
fetch_sync = async_to_sync(fetch_data)

def handle(self, *args, **options):
    data = fetch_sync("https://api.example.com")  # 阻塞等待,但内部使用事件循环
    print(data)
限制
  • 不能在已有事件循环中使用(如在 async def 内调用)
    async def outer():
        async_to_sync(inner)()  # ❌ RuntimeError
    
  • 内部会创建并管理自己的事件循环(类似 asyncio.run()

四、底层机制简析

sync_to_async 如何工作?

  1. 将同步函数提交到专用线程池执行
  2. 如果 thread_sensitive=True
    • 使用单线程执行器(而非线程池)
    • 同一“上下文”(如同一请求)的所有调用复用同一线程
  3. 返回一个协程,await 时等待线程结果

async_to_sync 如何工作?

  1. 创建一个新的事件循环(如果不存在)
  2. 在该 loop 中运行异步函数
  3. 阻塞当前线程直到完成

这比直接用 asyncio.run() 更智能,尤其对 thread_sensitive 场景做了深度优化。


五、常见问题与陷阱

问题 1:在已有事件循环中使用 async_to_sync

async def view():
    async_to_sync(some_async_func)()  # ❌ RuntimeError

✅ 修复:直接 await some_async_func()


问题 2:误设 thread_sensitive=False 导致 Django ORM 错误

@sync_to_async(thread_sensitive=False)  # ❌ 危险!
def get_user():
    return User.objects.get(id=1)  # 可能报 "connection already closed"

✅ 修复:保持默认 thread_sensitive=True(Django 官方要求)


问题 3:嵌套转换导致性能下降

# 不要这样:
async_to_sync(sync_to_async(func))

✅ 修复:明确边界,避免来回转换


问题 4:忘记 await(sync_to_async 返回的是协程)

async def bad():
    result = sync_to_async(blocking_func)()  # 返回协程对象,未执行!
    print(result)  # <coroutine object...>

✅ 修复result = await sync_to_async(blocking_func)()


六、与原生 asyncio 方案对比

方案 适用场景 线程安全 Django ORM 兼容 推荐度
asgiref.sync.sync_to_async 通用同步→异步 ✅(可选 thread_sensitive) ✅✅✅(官方方案) ⭐⭐⭐⭐⭐
loop.run_in_executor() 简单阻塞任务 ❌(需手动管理线程) ❌(ORM 可能出错) ⭐⭐
asyncio.run() 顶层启动异步 ❌(不能嵌套) 不适用 ⭐⭐⭐

关键优势
asgiref 是唯一能保证 Django ORM 在异步中正确工作的方案


七、最佳实践

1. Django 用户必读

  • 所有对 ORM、缓存、session 的调用,必须用 @sync_to_async
  • 永远不要手动用 run_in_executor

2. 合理使用 thread_sensitive

  • 有状态操作(DB、缓存) → thread_sensitive=True(默认)
  • 无状态计算(hash、encode) → thread_sensitive=False(提升并发)

3. 避免在热路径频繁转换

  • 将转换逻辑封装在边界层(如 service 层),而非每次调用都转

4. 测试时注意

  • 在 pytest 中,使用 pytest-asyncio + 直接 await,而非 async_to_sync

八、完整示例:Django 异步视图 + ORM

# views.py
from django.http import JsonResponse
from asgiref.sync import sync_to_async
from .models import Article

@sync_to_async
def get_article_count():
    return Article.objects.count()  # 同步 ORM

@sync_to_async
def create_article(title):
    return Article.objects.create(title=title)

async def article_stats(request):
    count = await get_article_count()
    return JsonResponse({"total": count})

async def create_article_view(request):
    title = request.GET.get("title")
    article = await create_article(title)
    return JsonResponse({"id": article.id, "title": article.title})

此代码在 Django 3.1+ 中完全合法且安全。


九、总结

项目 说明
核心价值 安全桥接同步与异步世界,尤其保障 Django ORM 在异步中的正确性
两大工具 sync_to_async(同步→异步)、async_to_sync(异步→同步)
关键特性 thread_sensitive 保证线程局部状态一致性
主要场景 - Django 异步视图调用 ORM
- 同步脚本调用异步 API
- 任何混合异步/同步的项目
安装方式 通常随 Django 自动安装;单独安装:pip install asgiref
版本要求 Python 3.6+,asgiref ≥ 3.2(推荐 ≥ 3.5)

终极口诀
“异步调同步,用 sync_to_async
同步调异步,用 async_to_sync
Django ORM 必加 thread_sensitive=True!”

通过 asgiref.sync,你可以在享受异步高性能的同时,无缝使用庞大的同步生态(Django、SQLAlchemy、requests 等),是现代 Python 异步开发的必备桥梁工具

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐