1. 为什么需要异步编程?
当你在Python中遇到需要同时处理多个网络请求、文件读写或数据库查询的场景时,传统同步代码会像在快餐店排长队一样低效——每个顾客(任务)必须等前一个完全结束后才能开始。我在处理网页爬虫时就遇到过这种困境:200个页面请求按顺序执行,足足浪费了15分钟等待时间。
异步编程就像开设了多个收银台。服务员(事件循环)在某个顾客等待找零时,可以立即服务下一位顾客。以HTTP请求为例,同步方式耗时约N*单个请求时间,而异步可将总时间压缩到接近最慢的那个请求耗时。
2. 理解协程与事件循环
2.1 协程的本质
协程(coroutine)是异步编程的基本单元,它不同于传统函数的关键在于能暂停和恢复执行。想象你在玩一款文字冒险游戏:
python复制async def fetch_data():
print('开始下载') # 你的角色走到宝箱前
await asyncio.sleep(2) # 需要时间开锁(模拟IO等待)
print('下载完成') # 获得宝物
这里的await就像点击"继续游戏"按钮,期间CPU可以去处理其他协程。
2.2 事件循环工作机制
事件循环相当于交响乐指挥,它的工作流程是:
- 检查就绪的协程(如IO完成)
- 执行到下一个await处
- 挂起当前协程,转去执行其他就绪任务
- 循环直到所有任务完成
用代码表示核心逻辑:
python复制tasks = [fetch_data() for _ in range(3)]
asyncio.run(asyncio.wait(tasks)) # 启动事件循环
3. 关键语法深度解析
3.1 async/await组合拳
async def:声明一个协程函数,调用它不会立即执行,而是返回协程对象await:只能在协程内使用,表示"可暂停点"。常见可await对象包括:- 其他协程
- asyncio.sleep()
- 异步IO库方法(如aiohttp请求)
典型错误示例:
python复制# 错误!普通函数内不能使用await
def sync_func():
await asyncio.sleep(1
