当前位置: 首页 > news >正文

Python中的协程(Coroutine)

Python中的协程(Coroutine) 是一种轻量级的异步执行单元,主要用于解决IO密集型任务的性能问题。Python 3.5引入了 async/await 语法,使得协程变得简洁且易于使用。协程的核心是通过事件循环(Event Loop) 来调度任务,在等待外部操作(如网络请求、文件读写)时,自动切换到其他任务,从而提升程序的整体效率。


一、协程的基本概念

  1. 协程(Coroutine)

    • 是一个暂停和恢复执行的函数,通过 async def 定义。
    • 协程不会阻塞整个事件循环,而是通过 await 关键字主动让出控制权。
    • 协程本身不会自动运行,需要通过事件循环(如 asyncio)来驱动。
  2. 事件循环(Event Loop)

    • 是协程调度的核心,负责管理任务的执行顺序、IO事件的监听和处理。
    • Python标准库 asyncio 提供了事件循环的实现。

二、协程的常见用法

1. 定义和运行协程
import asyncioasync def my_coroutine():print("Coroutine started")await asyncio.sleep(1)  # 模拟耗时操作(如IO)print("Coroutine finished")# 运行协程
asyncio.run(my_coroutine())  # Python 3.7+ 推荐
2. 使用 asyncawait
  • async def:定义一个协程函数。
  • await:在协程内部调用另一个协程,当遇到 await 时,当前协程暂停,让出控制权。
async def fetch_data():print("Start fetching")await asyncio.sleep(2)  # 模拟网络请求return "Data"async def main():result = await fetch_data()  # 等待fetch_data完成print(result)  # 输出:Dataasyncio.run(main())
3. 并发执行多个协程

使用 asyncio.gather() 并发运行多个协程:

async def task1():await asyncio.sleep(1)return "Task1 Done"async def task2():await asyncio.sleep(2)return "Task2 Done"async def main():results = await asyncio.gather(task1(), task2())print(results)  # 输出:["Task1 Done", "Task2 Done"]asyncio.run(main())
4. 异步迭代和上下文管理器
  • 异步生成器:通过 async for 迭代异步序列。
  • 异步上下文管理器:通过 async with 管理资源。
# 异步生成器示例
async def async_gen():for i in range(3):await asyncio.sleep(1)yield iasync def main():async for item in async_gen():print(item)  # 输出0, 1, 2# 异步上下文管理器示例(如打开文件)
async with aiofiles.open("file.txt", mode="r") as f:content = await f.read()

三、常用协程类库

以下是Python中常用的协程相关库及典型用法:

1. asyncio(标准库)

Python内置的异步事件驱动框架,提供协程、事件循环、Future/Task等核心功能。

  • 核心组件
    • Event Loop:事件循环管理器(如 asyncio.get_event_loop())。
    • Task:将协程封装为任务,以便在事件循环中调度。
    • Future:表示异步操作的最终结果。
  • 典型用法
    async def hello():print("Hello")await asyncio.sleep(1)print("World")# 获取事件循环并运行
    loop = asyncio.get_event_loop()
    loop.run_until_complete(hello())  # 或 asyncio.run(hello())
    
2. aiohttp

基于 asyncio 的异步HTTP客户端和服务器库,适用于高性能Web爬虫或Web服务。

  • 客户端用法
    import aiohttpasync def fetch():async with aiohttp.ClientSession() as session:async with session.get("https://api.example.com/data") as response:return await response.json()asyncio.run(fetch())
    
  • 服务器用法
    from aiohttp import webasync def handle(request):return web.Response(text="Hello, Aiohttp!")app = web.Application()
    app.router.add_get("/", handle)
    web.run_app(app)
    
3. asyncpg

用于 PostgreSQL 的异步数据库驱动,适用于异步数据库操作。

import asyncpgasync def main():conn = await asyncpg.connect(user='user', password='password',database='db', host='127.0.0.1')values = await conn.fetch("SELECT * FROM my_table")await conn.close()asyncio.run(main())
4. aiofiles

异步文件操作库,替代 open() 函数,适用于大文件处理或需要异步读写的场景。

import aiofilesasync def read_file():async with aiofiles.open("large_file.txt", mode="r") as f:content = await f.read()print(content)
5. gevent

基于 greenlet 的协程库,通过协程模拟多线程,支持同步代码异步化(非async/await语法)。

import gevent
from gevent import monkey; monkey.patch_all()  # 打补丁def task(name, n):for i in range(n):print(f"{name}: {i}")gevent.sleep(0.1)gevent.joinall([gevent.spawn(task, "A", 3),gevent.spawn(task, "B", 5)
])

四、协程 vs 线程/进程

特性协程多线程多进程
资源消耗极低(共享线程/进程资源)中(线程资源)高(进程资源)
切换方式用户态协作式切换内核级抢占式切换内核级抢占式切换
适合场景IO密集型(如网络请求、文件)轻量级并发(如小计算任务)CPU密集型(如科学计算)
GIL影响在CPython中受GIL限制受GIL限制不受GIL限制(每个进程独立)

五、最佳实践与注意事项

  1. 避免阻塞操作:协程内部应避免长时间阻塞(如 time.sleep()),改用 asyncio.sleep()
  2. 合理使用 await:确保在协程中正确使用 await,否则代码不会异步执行。
  3. 错误处理:使用 try/except 捕获异步操作的异常。
  4. 调试:协程的调试较复杂,建议使用 asyncio.debug 或专用调试工具。
  5. 库的兼容性:非异步库需要通过 loop.run_in_executor() 转换为异步操作。

六、典型应用场景

  1. Web爬虫:并发请求多个网页,异步处理响应。
  2. 实时数据处理:如股票行情、物联网传感器数据流。
  3. 高性能服务器:构建异步HTTP服务器或WebSocket服务。
  4. 游戏或模拟器:需要处理大量并发事件的场景。

七、扩展学习资源

  1. 官方文档
    • asyncio:https://docs.python.org/3/library/asyncio.html
    • aiohttp:https://aiohttp.readthedocs.io/
  2. 书籍
    • 《Fluent Python》第22章(协程和事件循环)。
    • 《Python异步编程实战》(异步IO、协程及框架应用)。

通过合理使用协程和相关库,可以显著提升Python在IO密集型任务中的性能和响应能力!

相关文章:

  • django admin 去掉新增 删除
  • 秒杀系统 Kafka 架构进阶优化
  • 用Node.js施展文档比对魔法:轻松实现Word文档差异比较小工具,实现Word差异高亮标注(附完整实战代码)
  • [原创](现代Delphi 12指南):[macOS 64bit App开发]: NSString类型与CFStringRef类型字符串相互转换.
  • Cursor 和Trae 产品使用及MCP应用
  • 【操作系统原理07】输入/输出系统
  • 部署mongodb三幅本集群
  • 02_值相同、类型不同,用 equals() 比较为什么是 false?
  • ipa包安装到apple手机上
  • 单片机-89C51部分:5、点亮LED
  • cocos creator使用jenkins打包流程,打包webmobile
  • python连接Elasticsearch并完成增删改查
  • 2.4java运算需要注意的细节
  • JS-OCR-demo加载本地文件
  • springboot当中的类加载器
  • C20-breakcontinue
  • AOSP Android14 Launcher3——动画核心类QuickstepTransitionManager详解
  • OneNet云平台
  • 创建laravel 12项目
  • [GXYCTF2019]Ping Ping Ping
  • 人社部:就业政策储备充足,将会根据形势变化及时推出
  • IPO周报|4月最后2只新股周一申购,今年以来最低价股来了
  • 油电同智,安全超充!从上海车展看中国汽车产业先发优势
  • 央媒关注给保洁人员设休息室:让每一份踏实奋斗得到尊重呵护
  • “70后”通化市委书记孙简已任吉林省政府领导
  • 税务部门曝光3起通过拆分经营骗享小规模纳税人税费优惠偷税案件