python异步asyncio库

代码完整分析

python

import asyncio
import time

async def fetch_api(idx: int, delay: int):
print(f"[{idx}] 开始请求...")
# asyncio.sleep 模拟非阻塞 I/O
await asyncio.sleep(delay)
print(f"[{idx}] 响应完成!")
return f"Result {idx}"

async def main():
# 1. 包装为 Task,立即注册到事件循环
t1 = asyncio.create_task(fetch_api(1, 2))
t2 = asyncio.create_task(fetch_api(2, 1))

2. 等待两个任务全部完成

await asyncio.gather(t1, t2)

asyncio.run(main())

  1. 核心概念解释

1.  async def :定义协程函数,调用它不会直接执行代码,只会生成一个协程对象。
2.  await :暂停当前协程,让出事件循环,去跑别的任务;等待后面这个IO操作完成之后,再回来继续执行。

await asyncio.sleep(delay) :非阻塞休眠,不会卡住整个程序,事件循环可以调度其他任务运行。
⚠️ 区分: time.sleep()  是阻塞休眠,会把整个事件循环卡死,异步代码里不能用。

3.  asyncio.create_task() 
把协程包装成Task任务,立刻提交给事件循环排队执行。
重点:创建t1、t2这两行代码一跑完,两个任务就已经并发启动了,不是等到await的时候才开始。
4.  asyncio.gather(t1,t2) :等待传入的所有任务全部执行完毕。
5.  asyncio.run(main()) :Python3.7+,用来启动事件循环,入口函数。

  1. 运行输出 & 时序(非常关键)

任务:

  • t1:fetch_api(1, 2) 休眠2秒
  • t2:fetch_api(2, 1) 休眠1秒

打印顺序:

plaintext

[1] 开始请求...
[2] 开始请求...
[2] 响应完成!
[1] 响应完成!

✅ 总耗时≈2秒(不是 2+1=3秒!并发)
时序拆解:

1. 执行 create_task(t1) :任务1启动,打印 [1]开始请求 ,碰到 await sleep(2)  → 任务1挂起,交出控制权
2. 执行 create_task(t2) :任务2启动,打印 [2]开始请求 ,碰到 await sleep(1)  → 任务2挂起
3. 事件循环等待:1秒后,t2休眠结束,t2恢复执行,打印 [2]响应完成 
4. 再过1秒(总共2s),t1休眠结束,打印 [1]响应完成

这就是异步IO的优势:IO等待的时候,CPU可以切换跑别的任务,不用傻傻等。

  1. 容易踩坑的知识点

对比:如果不使用create_task,直接await

python

串行版本!总耗时3秒

await fetch_api(1,2)
await fetch_api(2,1)

会先跑完第一个,等2秒结束,才跑第二个,总时间叠加。

create_task  是实现并发的关键。

补充:gather也可以直接接收协程

python

简写写法,不用手动创建task

await asyncio.gather(
fetch_api(1,2),
fetch_api(2,1)
)

内部gather会自动帮你创建Task,效果等价。

  1. 代码缺陷&改进点

1. 当前代码没有拿到返回值,gather会收集所有return结果,可以这样改:

python

res = await asyncio.gather(t1, t2)
print(res) # ['Result 1', 'Result 2']

2. 没有异常捕获:如果fetch_api里面报错,程序直接崩溃,可以加 try/except 。
3.  asyncio.sleep  只模拟IO等待,异步不能加速CPU密集运算(CPU计算时不会主动让出循环)。

一句话总结

这段代码演示了asyncio基于事件循环的IO并发:两个模拟API请求同时发起,IO等待期间切换任务,总时间由最长任务决定。

posted @ 2026-10-05 16:01  立体风  阅读(3)  评论(0)    收藏  举报