共计 1397 个字符,预计需要花费 4 分钟才能阅读完成。
协程(Coroutine)是一种比线程更轻量级的单元,它让我们能够以同步的写法实现异步的效果。与线程不同,协程本质上是用户态的“微线程”,由程序自行调度,而不是由操作系统进行调度,因此开销更低、性能更高。
一、为什么需要协程?
在处理 I/O 密集型任务时(例如网络请求、文件读写),程序会大量时间处于等待状态。
如果使用同步代码,等待会阻塞整个程序流程。
协程允许程序在遇到 I/O 阻塞时主动让出控制权,让其他任务运行,从而提高整体运行效率。
二、协程的基本语法:async 与 await
Python 从 3.5 开始引入原生协程语法:
import asyncio
async def hello():
print("开始执行...")
await asyncio.sleep(1)
print("执行结束!")
asyncio.run(hello())
代码解析
- async:定义一个协程函数
- await:等待一个耗时操作,并让出控制权
三、多个协程并发执行
协程真正的力量来自于“并发”,例如同时执行多个任务:
import asyncio
async def task(name, sec):
print(f"{name} 开始")
await asyncio.sleep(sec)
print(f"{name} 完成")
async def main():
await asyncio.gather(task("任务 1", 1),
task("任务 2", 2),
task("任务 3", 1)
)
asyncio.run(main())
效果
- 三个任务会并发执行
- 总耗时约 2 秒,而不是 1 + 2 + 1 = 4 秒
四、事件循环(Event Loop)
事件循环负责调度和运行协程,是协程背后的核心机制。
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
从 Python 3.7 开始,推荐使用更简单的:
asyncio.run(main())
五、协程的典型使用场景
1. 大量网络请求
如爬虫、接口聚合、批量 API 请求等。
2. Web 框架(如 FastAPI、aiohttp)
使用协程提升并发能力。
3. 高并发任务调度
协程让 Python 在 I/O 密集型任务中非常高效。
六、协程实战:并发爬取网页标题
import asyncio
import aiohttp
async def fetch_title(session, url):
async with session.get(url) as resp:
text = await resp.text()
print(f"获取到内容:{url[:30]}...")
async def main():
urls = [
"https://www.python.org/",
"https://www.google.com/",
"https://www.github.com/"
]
async with aiohttp.ClientSession() as session:
tasks = [fetch_title(session, url) for url in urls]
await asyncio.gather(*tasks)
asyncio.run(main())
七、小结
- 协程是 I/O 密集型任务的利器,比线程更轻量
- async/await 是核心语法
- asyncio.gather 用于并发执行多个协程
- 协程通过事件循环统一调度执行
- 常用于爬虫、网络服务与高并发业务场景
正文完