Python 异步编程实战:async/await 从入门到精通
前言
在如今的 Web 开发和网络编程中,异步编程已经成为必备技能。Python 3.5+ 引入的 `async/await` 语法让异步代码变得像同步代码一样易读。本文将带你从零开始掌握 Python 异步编程的核心概念和实战技巧。
一、什么是异步编程?
异步编程是一种编程范式,允许程序在等待某些操作(如网络请求、文件读写)完成时,转而执行其他任务,而不是阻塞等待。
同步 vs 异步
```python
同步代码 - 阻塞式
import time
def fetch_data_sync():
print("开始获取数据...")
time.sleep(2) # 阻塞 2 秒
print("数据获取完成")
return "data"
fetch_data_sync()
fetch_data_sync() # 必须等第一个完成才能执行第二个
总耗时:4 秒
```
```python
异步代码 - 非阻塞式
import asyncio
async def fetch_data_async():
print("开始获取数据...")
await asyncio.sleep(2) # 非阻塞等待
print("数据获取完成")
return "data"
async def main():
两个任务并发执行
results = await asyncio.gather(
fetch_data_async(),
fetch_data_async()
)
return results
asyncio.run(main())
总耗时:2 秒
```
二、核心概念解析
1. async 和 await
-
`async`:定义一个协程函数
-
`await`:等待一个协程执行完成
```python
import asyncio
async def say_hello():
await asyncio.sleep(1)
return "Hello"
async def say_world():
await asyncio.sleep(1)
return "World"
async def main():
顺序执行 - 耗时 2 秒
result1 = await say_hello()
result2 = await say_world()
print(f"{result1} {result2}")
并发执行 - 耗时 1 秒
results = await asyncio.gather(
say_hello(),
say_world()
)
print(f"{results[0]} {results[1]}")
asyncio.run(main())
```
2. Task - 调度和管理协程
```python
import asyncio
async def worker(name, delay):
for i in range(3):
await asyncio.sleep(delay)
print(f"{name} 执行第 {i+1} 次")
async def main():
创建任务
task1 = asyncio.create_task(worker("任务 A", 1))
task2 = asyncio.create_task(worker("任务 B", 1.5))
等待所有任务完成
await asyncio.gather(task1, task2)
print("所有任务完成")
asyncio.run(main())
```
三、实战案例:异步网络请求
使用 aiohttp 进行并发 HTTP 请求
```python
import asyncio
import aiohttp
async def fetch_url(session, url):
"""异步获取单个 URL 内容"""
try:
async with session.get(url) as response:
content = await response.text()
return f"{url}: {len(content)} 字节"
except Exception as e:
return f"{url}: 错误 - {e}"
async def fetch_all_urls(urls):
"""并发获取多个 URL"""
async with aiohttp.ClientSession() as session:
tasks = [fetch_url(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
async def main():
urls = [
"https://www.stackoverflow.com"
]
results = await fetch_all_urls(urls)
for result in results:
print(result)
asyncio.run(main())
```
四、异步编程最佳实践
1. 避免阻塞操作
```python
❌ 错误示例 - 在异步函数中使用同步阻塞
async def bad_example():
import time
await asyncio.sleep(0)
time.sleep(1) # 这会阻塞整个事件循环!
✅ 正确示例 - 使用异步替代方案
async def good_example():
await asyncio.sleep(1) # 非阻塞等待
```
2. 使用 Semaphore 控制并发数
```python
async def fetch_with_limit(sem, url):
async with sem: # 限制同时进行的请求数
return await fetch_url(url)
async def main():
sem = asyncio.Semaphore(5) # 最多 5 个并发
urls = ["http://example.com"] * 100
tasks = [fetch_with_limit(sem, url) for url in urls]
await asyncio.gather(*tasks)
```
3. 超时处理
```python
async def fetch_with_timeout(url, timeout=5):
try:
async with asyncio.timeout(timeout):
return await fetch_url(url)
except asyncio.TimeoutError:
return f"{url} 请求超时"
```
五、性能对比
| 场景 | 同步方式 | 异步方式 | 提升 |
|------|---------|---------|------|
| 100 个 HTTP 请求 | ~100 秒 | ~2 秒 | 50 倍 |
| 数据库批量查询 | ~50 秒 | ~3 秒 | 16 倍 |
| 文件并发读写 | ~20 秒 | ~5 秒 | 4 倍 |
总结
Python 异步编程的核心优势:
-
**高并发**:单线程处理大量 I/O 密集型任务
-
**资源节省**:不需要为每个连接创建线程
-
**代码清晰**:async/await 让异步代码像同步一样易读
-
**生态成熟**:aiohttp、asyncpg、aiomysql 等库支持完善
**适用场景**:
-
Web 爬虫
-
API 网关
-
实时数据处理
-
WebSocket 服务
**不适用场景**:
-
CPU 密集型计算(考虑多进程)
-
简单的脚本任务
掌握异步编程,让你的 Python 应用性能起飞!🚀
*如果觉得本文有帮助,欢迎点赞收藏!有问题请在评论区留言~*