详细摘要 摘要
生成:2025-06-21 18:33摘要详情
- 音频文件
- 2022-10-17 | DjangoCon 2022 | Async Django: The practical guide you've been **awaiting** for.
- 摘要类型
- 详细摘要
- LLM 提供商
- openai
- LLM 模型
- gemini-2.5-pro
- 温度
- 0.3
- 已创建
- 2025-06-21 18:33:45
摘要内容
概览/核心摘要 (Executive Summary)
本次演讲由 Django Fellow Carlton Gibson 主讲,旨在为 Django 开发者提供一份关于异步(Async)编程的实用指南。演讲核心观点是,虽然异步是一个庞大且复杂的话题,但 Django 开发者无需深入底层细节,即可利用其强大功能增强现有应用。演讲首先简要介绍了 Python asyncio 库的核心概念,如事件循环、async/await 语法和协程,并澄清了使用 asyncio.create_task 实现后台任务的局限性——它缺乏健壮的错误处理机制,且依赖于持续运行的 ASGI 服务器环境,在传统 WSGI 部署下会立即退出。
演讲重点展示了两个核心实用模式:
1. 聚合视图 (Aggregating Views):一种无需引入 GraphQL 即可解决前端需一次性获取多源数据问题的模式。通过在 async def 视图中使用 httpx 等异步客户端并发请求多个内部 API,可显著提升性能。此模式的最大优势是可直接在现有的 WSGI 应用中使用,为开发者提供了一个低风险的切入点。
2. 实时更新应用:以聊天应用为例,系统性地对比了四种实现实时更新的策略:
* 轮询 (Polling):最简单,但有扩展性和延迟问题。
* 长轮询 (Long Polling)、服务器发送事件 (Server-Sent Events - SSE) 和 WebSockets:这三种是基于事件的异步方案,需要借助 Django Channels 和 ASGI 服务器。演讲详细解释了它们的实现逻辑和优缺点,指出 WebSockets 是唯一支持双向通信的方案。
最后,演讲者给出了关键的部署建议:为降低风险,推荐采用混合部署模式,即核心应用继续使用成熟稳定的 WSGI,而将异步功能部署在独立的 ASGI 服务上。同时,他强烈建议对整个网络堆栈(从负载均衡器到应用)进行彻底测试,特别是针对长连接和空闲超时问题,并可通过心跳机制解决。
引言与背景
- 演讲者介绍: Carlton Gibson,Django Fellow 之一,负责 Django 框架的日常维护、安全问题处理和版本发布。他同时也是 Django Channels 等多个生态系统包的维护者。
- 演讲目的: 旨在消除社区对 Async Django 的困惑,通过实际案例展示如何在 Django 应用中务实地引入异步功能,而无需深入研究其复杂的底层实现。演讲者强调,开发者只需了解相关概念,即可利用异步为应用增值。
Asyncio 核心概念入门
演讲首先通过一个简单的示例介绍了 Python 标准库 asyncio 的基本用法,它是 Django 异步支持的基础。
- 核心组件:
asyncio模块: Python 的标准异步运行时,提供事件循环(Event Loop)来调度并发任务。async def: 用于定义一个协程函数 (Coroutine Function)。调用它不会立即执行代码,而是返回一个协程对象。await: 用于暂停当前协程的执行,将控制权交还给事件循环,等待一个“可等待对象”(如另一个协程或 I/O 操作)完成。
- 关键函数:
asyncio.create_task(): 将一个协程作为任务安排到事件循环上并发执行,但它本身不处理错误或重试。asyncio.gather(): 等待多个任务全部完成。演讲者强调这是一个关键步骤,> “如果你不等待任务完成,主函数会直接退出,事件循环随之关闭,所有后台任务都将被终止。”
关键问题:Async 能否用于后台任务?
对于“能否使用 asyncio.create_task 来处理后台任务(如发送注册邮件)”这一常见问题,演讲者给出了一个审慎的回答:“可以,但这取决于情况 (it kind of, and it depends)”。
-
观点一:“可以,但有局限 (Kind of)”
- 缺乏健壮性:
asyncio.create_task本身不提供任何错误处理、状态跟踪或重试机制。如果任务失败,需要开发者自行编写大量代码来确保其鲁棒性。 - 替代方案: 对于需要高可靠性的后台任务,使用成熟的任务队列如 Celery 或 Django-Q 是更明智的选择。
- 缺乏健壮性:
-
观点二:“取决于你的运行方式 (It depends)”
- WSGI vs. ASGI:
- WSGI (Web Server Gateway Interface): 传统的同步 Python Web 应用标准。在 WSGI 模式下,当 Django 遇到一个
async def视图时,它会为该请求临时启动一个事件循环,视图返回响应后,事件循环立即关闭。 - ASGI (Asynchronous Server Gateway Interface): 现代的异步标准,支持长连接和事件驱动。在 ASGI 模式下,存在一个持续运行的事件循环。
- WSGI (Web Server Gateway Interface): 传统的同步 Python Web 应用标准。在 WSGI 模式下,当 Django 遇到一个
- 结论: 只有在 ASGI 服务器(如 Daphne 或 Uvicorn)下,才有一个持续运行的事件循环来保证
create_task创建的后台任务在主请求结束后能继续执行。在 WSGI 下,这些任务会随着请求的结束而被中断。
- WSGI vs. ASGI:
实用模式一:聚合视图 (Aggregating Views)
这是一个演讲者高度推荐的模式,他称之为 > “我们在 GraphQL 出现之前就已经在做的事情”。
- 问题场景: 移动端或前端需要在一个页面上展示来自多个数据源的信息(例如,酒店详情和其所有房间列表),但出于性能和可靠性考虑,不希望发起多次网络请求。
- 解决方案: 创建一个单一的
async def视图,该视图作为聚合器。- 导入异步客户端: 使用如
httpx这样的异步 HTTP 请求库。 - 定义异步视图: 在 Django 4.1+ 中,可以在类视图中直接定义
async def方法。 - 并发获取数据: 使用
httpx.AsyncClient和asyncio.gather并发地请求应用内部的其他 API 端点(如酒店详情 API 和房间列表 API)。 - 组合并返回: 等待所有内部请求完成后,将数据组合成前端需要的单一 JSON 结构并返回。
- 导入异步客户端: 使用如
- 核心优势:
- 无需改变部署架构: 这是该模式最吸引人的地方。> “你可以立刻在你现有的 WSGI 应用中实现它……Django 会为这个聚合视图单独启动一个事件循环,而你应用的其他部分保持不变。”
- 性能提升: 将串行的网络请求变为并行,总响应时间取决于最慢的那个内部请求,而不是所有请求时间之和。
实用模式二:构建实时更新的聊天应用
演讲通过一个聊天应用的例子,详细对比了四种实现“实时更新”的策略,展示了异步需求的演进过程。
基础设置
- 一个简单的
Message模型。 - 一个标准的 Django
ListView用于展示消息列表,一个CreateView用于提交新消息。
策略一:轮询 (Polling)
- 实现: 使用前端技术(如 HTMX)每隔固定时间(如 5 秒)向服务器请求最新的消息列表。
- 优点:
- 实现极其简单,无需修改后端架构。
- 完全兼容传统的 WSGI 部署。
- 缺点:
- 扩展性差: 大量客户端同时轮询会产生巨大流量,演讲者称之为 > “你基本上是在对自己进行 DDoS 攻击”。
- 响应性差: 存在明显的延迟(取决于轮询间隔)。
引入 Django Channels
当轮询无法满足需求时,就需要转向事件驱动的异步方案,这需要引入 Django Channels。
* Channel Layer: 一个通信层(通常基于 Redis),允许在应用的不同实例或进程之间广播消息。
* Consumers: 类似于 Django 的视图,但用于处理 ASGI 事件(如 HTTP 请求或 WebSocket 连接)。它们提供了比直接操作 ASGI 更友好、更像 Django 的编程模型。
策略二:长轮询 (Long Polling)
- 实现:
- 客户端发起一个请求。
- 服务器(通过
AsyncHttpConsumer)收到请求后不立即响应,而是保持连接打开,并订阅 Channel Layer 中的一个群组。 - 当有新消息发布时,通过 Channel Layer 广播通知。
- Consumer 收到通知后,查询新数据,渲染模板,并将响应发送给客户端,然后关闭连接。
- 优点: 响应及时,一旦有新消息立即推送。
- 缺点: 客户端在收到响应后通常会立即发起新的长轮询请求,仍然存在连接建立和销毁的开销。
策略三:服务器发送事件 (Server-Sent Events - SSE)
- 实现: 与长轮询非常相似,但关键区别在于,当服务器发送一个更新后,它不会关闭连接(通过设置
more_body=True)。连接会保持开放,以便后续可以推送更多更新。 - 优点: 相比长轮询,大大减少了重复建立连接的开销,更高效。
- 缺点: 通信是单向的(服务器到客户端)。
策略四:WebSockets
- 实现: 使用
WebsocketConsumer建立一个持久的、双向的连接。服务器可以向客户端推送更新,客户端也可以通过同一连接向服务器发送数据。 - 优点:
- 功能最强大,支持双向实时通信。
- 是构建复杂实时应用(如在线协作、游戏)的首选。
- 生态系统成熟,有大量前端库支持。
- 缺点: 实现相对复杂一些。
策略对比与选择
- 简单场景: 如果客户端不多,延迟要求不高,轮询就足够了。
- 单向实时推送: SSE 通常是比长轮询更好的选择。
- 双向实时通信: 必须使用 WebSockets。
- 务实选择: 最终选择也可能取决于你使用的前端库对哪种技术的支持更好。
部署与运维建议
- 混合部署策略: > “将你的核心应用部署在 WSGI 上,就像你现在做的一样,然后只将你的异步代码放在一个旁路的 ASGI 应用中。” 这种方式可以利用 WSGI 的稳定性和成熟生态,同时将异步功能的风险隔离。
- 全面测试: 异步应用的问题常常出在部署环境上,而非代码本身。必须彻底测试整个堆栈:
- 负载均衡器 (Load Balancer): 是否正确配置了长连接支持?
- Web 服务器 (Web Server): HTTP 版本是否正确?WebSocket 升级是否正常?
- 空闲超时 (Idle Timeout): 检查各层(负载均衡器、反向代理)的连接超时设置。一个常见的陷阱是空闲连接被过早断开。
- 使用心跳机制 (Heartbeats): 为了防止空闲连接被网络设备断开,可以定期(例如每 20 秒)从服务器发送一个小的“心跳”消息,以保持连接活跃。
结论
演讲的最后,Carlton Gibson 鼓励开发者们拥抱并享受探索异步编程的乐趣。Async Django 提供了强大的能力,开发者可以从低风险、高回报的模式(如聚合视图)开始尝试,逐步为自己的应用添加更高级的实时功能。