当前位置: 首页 > news >正文

Python 异步编程:await、asyncio.gather 和 asyncio.create_task 的区别与最佳实践

在现代 Python 开发中,异步编程几乎已经成为标配,尤其是在需要处理 I/O 密集型任务(如网络请求、数据库查询、LLM 调用)的场景。
但是很多同学在写异步代码时,经常搞不清楚 awaitasyncio.gatherasyncio.create_task 的区别。

1. await 是什么?

await 的本质是:运行一个协程,等待它返回结果。

如果你写:

result = await some_async_function()

等价于“我要执行 some_async_function,并且在它完成之前,当前协程不往下走”。
如果不写 await,拿到的只是一个 coroutine 对象,它不会真正执行。

示例

import asyncioasync def foo():print("foo start")await asyncio.sleep(1)print("foo end")return 42async def main():coro = foo()print("没有 await:", coro)result = await foo()print("有 await:", result)asyncio.run(main())

输出:

没有 await: <coroutine object foo at 0x...>
foo start
foo end
有 await: 42

 结论

  • await 是必须的,否则协程不会执行。

  • 如果有多个 await,它们是 顺序执行 的。

2. asyncio.gather:让多个任务并发执行

如果你有多个异步任务,但希望它们并发执行(而不是顺序),就用 asyncio.gather

示例

import asyncioasync def foo(name, delay):print(f"{name} start")await asyncio.sleep(delay)print(f"{name} end")return nameasync def main():results = await asyncio.gather(foo("A", 2),foo("B", 2),)print("结果:", results)asyncio.run(main())

输出:

A start
B start
A end
B end
结果: ['A', 'B']

两个任务 并发执行,总耗时 2 秒,而不是 4 秒。

3. asyncio.create_task:更灵活的任务调度

gather 适合“一次性并发并收集结果”。
如果你希望任务 后台运行,并在合适的时机再获取结果,就要用 create_task

示例

import asyncioasync def foo(name, delay):print(f"{name} start")await asyncio.sleep(delay)print(f"{name} end")return nameasync def main():task1 = asyncio.create_task(foo("A", 2))task2 = asyncio.create_task(foo("B", 2))print("任务已创建,可以先做点别的事...")# 等待单个任务result1 = await task1result2 = await task2print("结果:", result1, result2)asyncio.run(main())

输出:

A start
B start
任务已创建,可以先做点别的事...
A end
B end
结果: A B

create_task 的好处:

  • 任务一旦创建就开始执行(不像 await 要等到被调用时才跑)。

  • 可以分开等待结果,适合 流式处理长时间运行的后台任务

4. 三者的对比

特性awaitasyncio.gatherasyncio.create_task
作用执行一个协程并等待结果并发执行多个协程并收集结果启动后台任务,稍后再等待
执行方式顺序并发(统一收集结果)并发(结果可灵活获取)
使用场景单个任务多个独立任务,结果要一起返回长时间任务、需要灵活调度

5. 实战:并发调用 LLM 接口

假设我们要并发调用大语言模型,问三个问题:

import asyncio
from autogen_core.models import UserMessage
from autogen_learn.llm_client import model_clientasync def ask(question: str):result = await model_client.create([UserMessage(content=question, source="user")])return resultasync def main():# 方法一:顺序(效率低)r1 = await ask("Capital of France?")r2 = await ask("Capital of Germany?")r3 = await ask("Capital of Japan?")print(r1, r2, r3)# 方法二:gather 并发(推荐)results = await asyncio.gather(ask("Capital of France?"),ask("Capital of Germany?"),ask("Capital of Japan?"))print(results)# 方法三:create_task(更灵活)task1 = asyncio.create_task(ask("Capital of France?"))task2 = asyncio.create_task(ask("Capital of Germany?"))task3 = asyncio.create_task(ask("Capital of Japan?"))print("任务已发出,可以先处理别的逻辑…")answers = [await task1, await task2, await task3]print(answers)await model_client.close()asyncio.run(main())
  • 如果要 一次性并发多个请求gather 更合适。

  • 如果要 分批处理结果,或边发边收create_task 更灵活。

6. 总结

  • await:运行并等待一个任务,默认是顺序执行。

  • asyncio.gather:并发执行多个任务,等待所有完成。

  • asyncio.create_task:任务一创建就执行,可以灵活等待结果,适合流式或后台任务。

如果你只是想并发几个请求,用 gather 就够了。
如果你要调度复杂任务,create_task 会更好。

http://www.xdnf.cn/news/1390375.html

相关文章:

  • 【DeepSeek】公司内网部署离线deepseek+docker+ragflow本地模型实战
  • 软考-系统架构设计师 办公自动化系统(OAS)详细讲解
  • 【C语言】深入理解指针(2)
  • [打包压缩] gzip压缩和解压缩介绍
  • webservice在进行run maven build中出现java.lang.ClassCastException错误
  • C++基础(⑤删除链表中的重复节点(链表 + 遍历))
  • 【C++闯关笔记】STL:vector的学习与使用
  • Spring Security 传统 web 开发场景下开启 CSRF 防御原理与源码解析
  • CorrectNav:用错误数据反哺训练的视觉语言导航新突破
  • Apache服务器IP 自动跳转域名教程​
  • electron-vite 配合python
  • UPDF for mac PDF编辑器
  • JAVA:Spring Boot 集成 Easy Rules 实现规则引擎
  • 来自火山引擎的 MCP 安全授权新范式
  • 嵌入式Linux驱动开发:i.MX6ULL按键中断驱动(非阻塞IO)
  • PostgreSQL15——子查询
  • 基于SQL大型数据库的智能问答系统优化
  • Emacs 多个方便查看函数列表的功能
  • QML QQuickImage: Cannot open: qrc:/images/shrink.png(已解决)
  • 前端-初识Vue实例
  • Spring Boot Redis序列化全解析(7种策略)
  • 2024年06月 Python(四级)真题解析#中国电子学会#全国青少年软件编程等级考试
  • leetcode 461 汉明距离
  • 如何在FastAPI中玩转全链路追踪,让分布式系统故障无处遁形?
  • 基于MCP工具的开发-部署-上线与维护全流程技术实现与应用研究
  • 北斗导航 | PPP-RTK算法核心原理与实现机制深度解析
  • AI助力PPT创作:秒出PPT与豆包AI谁更高效?
  • TypeScript:map和set函数
  • 【前端教程】从基础到专业:诗哩诗哩网HTML视频页面重构解析
  • Java试题-选择题(21)