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 asyncio

async 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)  # 输出:Data

asyncio.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 i

async 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 aiohttp
    
    async 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 web
    
    async 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 asyncpg

async 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 aiofiles

async 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. 官方文档
  2. 书籍
    • 《Fluent Python》第22章(协程和事件循环)。
    • 《Python异步编程实战》(异步IO、协程及框架应用)。

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

您可能感兴趣的与本文相关的镜像

Python3.9

Python3.9

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

### Python 协程 Coroutine 使用教程与常见问题 #### 一、协程简介 协程是一种并发编程技术,它允许程序在执行过程中暂停和恢复。协程可以看作一种特殊的函数,能够暂停其执行去运行其他的任务,并能在之后返回到暂停处继续执行。相较于线程或进程而言,协程拥有更低的资源消耗以及更高的执行效率[^4]。 #### 二、使用 async 和 await 定义协程 `async` 和 `await` 是 Python 中用于定义和调用协程的关键字。这两个关键字使得编写异步代码变得更加简洁直观,有助于处理并发任务。下面是一个简单的例子来展示如何创建并启动一个基本的协程: ```python import asyncio async def say_after(delay, what): await asyncio.sleep(delay) print(what) async def main(): task1 = say_after(1, 'hello') task2 = say_after(2, 'world') # Wait until both tasks are completed (should take around 2 seconds.) await task1 await task2 # Run the event loop to execute coroutines. asyncio.run(main()) ``` 这段代码展示了两个延迟打印语句的任务被安排在一个事件循环里依次完成;其中每个任务都会等待指定的时间间隔后再输出相应的内容[^1]。 #### 三、利用 asyncio 编写并发异步代码 `asyncio` 模块提供了丰富的工具支持开发者构建复杂的异步应用程序。除了上述提到的基础功能外,还包含了诸如队列、锁机制等功能组件帮助管理多任务间的协作关系。这里给出一段更加复杂一点的例子说明如何同时发起多个 HTTP 请求而不阻塞主线程的工作流程: ```python import aiohttp import asyncio async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(urls): async with aiohttp.ClientSession() as session: results = await asyncio.gather(*[fetch(session, url) for url in urls]) for result in results: print(result[:100]) # Print first 100 characters of each page. urls = ["https://example.com", "https://www.python.org"] asyncio.run(main(urls)) ``` 此段脚本会向给定 URL 列表发送 GET 请求并将接收到的数据部分显示出来。值得注意的是整个过程是在同一个线程内高效地完成了多项I/O操作而无需担心传统同步模式下可能产生的性能瓶颈问题[^2]。 #### 四、Gevent 库介绍及其应用场景 对于那些希望简化开发工作量又不想深入研究底层细节的人来说,`gevent` 可能是个不错的选择。该库基于 `greenlet` 构建而成并通过所谓的“猴子补丁”实现了透明化控制流转移的效果——即当某个绿色线程处于休眠状态时操作系统将会自动切换至下一个可运行实例上继续推进整体进度直至所有待办事项都被妥善处置完毕为止。特别是在面对大量短时间内的高频率交互请求(比如Web服务器端口监听)或是长时间占用外部资源的操作场合之下往往可以获得较为理想的吞吐率表现[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值