Python 异步编程实战:asyncio 从入门到生产级应用
Python 的 asyncio 模块从 3.4 版本引入,到现在已经成为高并发场景的标准方案。但很多开发者对它的理解还停留在"加个 await"的层面。
一、为什么需要异步
传统的同步代码在遇到 I/O 操作时会阻塞线程。当你需要同时请求 100 个 API 时:
- **同步方式**:串行执行,总耗时 = 100 × 单次耗时
- **异步方式**:并发执行,总耗时 ≈ 单次耗时(受并发数限制)
import asyncio
import aiohttp
async def fetch(session, url):
async with session.get(url) as resp:
return await resp.json()
async def main():
urls = [f"https://api.example.com/item/{i}" for i in range(100)]
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
二、事件循环的本质
事件循环是 asyncio 的心脏。它做的事情很简单:
- 从任务队列取出一个协程
- 运行它,直到遇到 `await`
- 把控制权交给事件循环
- 检查是否有 I/O 完成
- 如果有,恢复对应的协程
# 等价的底层写法
loop = asyncio.new_event_loop()
try:
loop.run_until_complete(main())
finally:
loop.close()
三、生产级最佳实践
3.1 控制并发数
无限制的并发会导致连接池耗尽或被目标服务限流:
semaphore = asyncio.Semaphore(10)
async def controlled_fetch(session, url):
async with semaphore:
return await fetch(session, url)
3.2 超时处理
try:
result = await asyncio.wait_for(fetch(session, url), timeout=5.0)
except asyncio.TimeoutError:
print(f"请求超时: {url}")
3.3 异常隔离
asyncio.gather 默认会在第一个异常时取消所有任务。生产环境建议用 return_exceptions=True:
results = await asyncio.gather(*tasks, return_exceptions=True)
for i, result in enumerate(results):
if isinstance(result, Exception):
print(f"任务 {i} 失败: {result}")
3.4 生命周期管理
async def background_task():
while True:
await do_work()
await asyncio.sleep(60)
async def app():
task = asyncio.create_task(background_task())
try:
await run_server()
finally:
task.cancel()
await task # 等待清理完成
四、常见误区
- **误区一**:异步一定比同步快。CPU 密集型任务用异步反而更慢,应该用 `multiprocessing`
- **误区二**:可以在异步代码里用 `time.sleep()`。这会阻塞整个事件循环,必须用 `asyncio.sleep()`
- **误区三**:所有库都有异步版本。很多库还是同步的,需要用 `run_in_executor` 包装
五、何时选择异步
| 场景 | 推荐方案 | |------|---------| | 高并发网络请求 | asyncio + aiohttp | | CPU 密集计算 | multiprocessing | | 混合场景 | asyncio + ProcessPoolExecutor | | 简单脚本 | 同步即可 |
异步不是银弹,但在 I/O 密集场景下,它能让你的程序性能提升一个数量级。


钱哆哆♥官方正规流量卡♥1 个月前
生死门虽繁星灿烂,但活着的人才是最重要。
钱哆哆♥官方正规流量卡♥1 个月前
《技术博客图文文章怎么做得不单一:封面、结构图与场景插图的组合方法》已更新:技术博客图文文章怎么做得不单一:封面、结构图与场景插图的组合方法 很多技术博客的正文其实不差,问题常常出在视觉层太单一。首页列表里大家都只有一张封面,点进去以后又是一大段连续文字,读者很难在几秒钟内判断这篇文章到底值不值得继续看。内容本身也许很扎实,但呈现方式没有把价值推出来。…
钱哆哆♥官方正规流量卡♥1 个月前
《技术博客图文文章怎么做得不单一:封面、结构图与场景插图的组合方法》已更新:技术博客图文文章怎么做得不单一:封面、结构图与场景插图的组合方法 很多技术博客的正文其实不差,问题常常出在视觉层太单一。首页列表里大家都只有一张封面,点进去以后又是一大段连续文字,读者很难在几秒钟内判断这篇文章到底值不值得继续看。内容本身也许很扎实,但呈现方式没有把价值推出来。…
钱哆哆♥官方正规流量卡♥1 个月前
《技术博客图文文章怎么做得不单一:封面、结构图与场景插图的组合方法》已更新:技术博客图文文章怎么做得不单一:封面、结构图与场景插图的组合方法 很多技术博客的正文其实不差,问题常常出在视觉层太单一。首页列表里大家都只有一张封面,点进去以后又是一大段连续文字,读者很难在几秒钟内判断这篇文章到底值不值得继续看。内容本身也许很扎实,但呈现方式没有把价值推出来。…
钱哆哆♥官方正规流量卡♥1 个月前
你和学霸的区别就是,你所有的灵光一闪,都是他的基本题型。