asyncio 是 Python 3.4+ 引入的标准库,用于编写并发代码。本文将带你快速入门 asyncio 的核心概念。
为什么要用异步?
在传统的同步编程中,当程序遇到 I/O 操作(如网络请求、文件读写)时,线程会阻塞等待。而异步编程允许我们在等待 I/O 时去执行其他任务,极大地提高了资源利用率。
核心概念
1. coroutine(协程)
使用 async def 定义的函数就是协程:
1 2 3 4 5 6 7 8 9
| import asyncio
async def say_hello(): print("Hello") await asyncio.sleep(1) print("World")
asyncio.run(say_hello())
|
2. await 关键字
await 用于等待一个可等待对象(协程、任务、Future)完成。注意:await 只能在 async def 函数中使用。
3. Task(任务)
任务用于并发调度协程:
1 2 3 4 5 6 7 8
| async def main(): task1 = asyncio.create_task(fetch_data("url1")) task2 = asyncio.create_task(fetch_data("url2")) result1 = await task1 result2 = await task2 print(result1, result2)
|
4. gather 并发执行
1 2 3 4 5 6 7
| async def main(): results = await asyncio.gather( fetch_data("url1"), fetch_data("url2"), fetch_data("url3"), ) print(results)
|
实战示例:并发爬虫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import asyncio import aiohttp
async def fetch(session, url): async with session.get(url) as response: return await response.text()
async def main(): urls = [ "https://api.github.com", "https://api.github.com/users/python", "https://api.github.com/users/google", ] 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)} bytes")
asyncio.run(main())
|
注意事项
- 不要在协程中使用阻塞操作:如
time.sleep(),应使用 asyncio.sleep()
- 事件循环:
asyncio.run() 会自动管理事件循环,高级用法可手动控制
- 异常处理:使用
try/except 包裹 await 语句
总结
asyncio 让 Python 也能高效处理 I/O 密集型任务。虽然学习曲线略陡,但掌握后能够编写出高性能的并发程序。
推荐阅读 官方文档 深入学习。