Python 异步编程实践¶
Python异步编程允许你在执行I/O操作(如网络请求、文件操作)时不阻塞主线程,从而提高程序的效率。本文将介绍Python中的异步编程基础和实践案例。
异步编程基础¶
什么是异步编程?¶
异步编程是一种编程模式,它允许程序在等待I/O操作完成时继续执行其他任务,而不是一直等待直到操作完成。
Python中的异步编程¶
Python 3.5+ 提供了以下异步编程支持:
async/await
语法asyncio
库- 异步上下文管理器和迭代器
asyncio 基本使用¶
创建协程¶
import asyncio
async def hello_world():
print("Hello")
await asyncio.sleep(1) # 模拟I/O操作
print("World")
# 运行协程
asyncio.run(hello_world())
并发运行多个协程¶
import asyncio
import time
async def say(what, delay):
await asyncio.sleep(delay)
print(what)
async def main():
print(f"开始时间: {time.strftime('%X')}")
# 并发运行协程
await asyncio.gather(
say("任务1", 1),
say("任务2", 2),
say("任务3", 3)
)
print(f"结束时间: {time.strftime('%X')}")
asyncio.run(main())
实际应用案例¶
异步网络请求¶
使用aiohttp
库进行异步HTTP请求:
import asyncio
import aiohttp
import time
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = [
"https://example.com",
"https://python.org",
"https://github.com",
"https://stackoverflow.com",
"https://pypi.org"
]
start_time = time.time()
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
for url, result in zip(urls, results):
print(f"{url}: 获取到 {len(result)} 字节的数据")
end_time = time.time()
print(f"总耗时: {end_time - start_time:.2f} 秒")
asyncio.run(main())
异步文件操作¶
使用aiofiles
库进行异步文件操作:
import asyncio
import aiofiles
async def read_file(file_path):
async with aiofiles.open(file_path, mode='r') as f:
return await f.read()
async def write_file(file_path, content):
async with aiofiles.open(file_path, mode='w') as f:
await f.write(content)
async def main():
# 读取文件
content = await read_file('input.txt')
# 处理内容
processed_content = content.upper()
# 写入文件
await write_file('output.txt', processed_content)
print("文件处理完成")
asyncio.run(main())
异步与多线程对比¶
异步编程和多线程都可以实现并发,但它们有很大区别:
特性 | 异步编程 | 多线程 |
---|---|---|
切换成本 | 低 | 高 |
内存占用 | 低 | 高 |
并行处理 | 不支持 | 支持 |
复杂度 | 中等 | 高 |
适用场景 | I/O密集型 | CPU密集型 |
最佳实践¶
- 使用适当的库:如
aiohttp
(网络),aiofiles
(文件),asyncpg
(数据库)等 - 避免阻塞操作:在异步函数中不要使用阻塞操作,如
time.sleep()
- 合理分组任务:使用
asyncio.gather()
或asyncio.TaskGroup
分组任务 - 使用超时控制:对可能耗时较长的操作设置超时
- 错误处理:合理处理异步操作中的异常
结语¶
Python异步编程在处理I/O密集型任务时非常高效,但也不是万能的。选择正确的工具来解决问题,有时候同步代码反而更简单易读。掌握异步编程思想和技巧,能帮助你写出更高效的Python程序。