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. 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+,用来启动事件循环,入口函数。
- 运行输出 & 时序(非常关键)
任务:
- 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可以切换跑别的任务,不用傻傻等。
- 容易踩坑的知识点
对比:如果不使用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. 当前代码没有拿到返回值,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等待期间切换任务,总时间由最长任务决定。

浙公网安备 33010602011771号