Python中的协程与异步IO模型
字数 779 2025-11-08 20:56:56

Python中的协程与异步IO模型

协程是Python异步编程的核心概念。让我从基础开始,循序渐进地讲解这个重要的知识点。

什么是协程

协程(Coroutine)是一种比线程更轻量级的并发编程方式。与线程不同,协程的切换由程序自身控制,而不是由操作系统调度。

协程的基本特点

  • 协作式多任务:协程主动让出执行权,而不是被强制中断
  • 单线程内并发:多个协程可以在单个线程内交替执行
  • 高效的上下文切换:协程切换不需要系统调用,开销极小

从生成器到协程

Python的协程是从生成器演化而来的。让我们看一个简单的例子:

def simple_coroutine():
    print("协程开始")
    x = yield  # 暂停点,接收外部传入的值
    print(f"接收到: {x}")
    y = yield x * 2  # 再次暂停,返回x*2
    print(f"再次接收到: {y}")

# 使用协程
coro = simple_coroutine()
next(coro)  # 启动协程,执行到第一个yield
result = coro.send(10)  # 发送10给协程,继续执行
print(f"返回结果: {result}")  # 输出: 返回结果: 20

async/await语法

Python 3.5引入了更清晰的async/await语法:

import asyncio

async def simple_async_coroutine():
    print("开始执行")
    await asyncio.sleep(1)  # 模拟IO操作
    print("1秒后")
    return "完成"

# 运行异步协程
async def main():
    result = await simple_async_coroutine()
    print(f"结果: {result}")

# 使用事件循环运行
asyncio.run(main())

事件循环(Event Loop)

事件循环是异步编程的核心引擎,负责调度和执行协程。

事件循环的工作原理

  1. 维护任务队列:管理待执行的协程任务
  2. 监控IO事件:通过selector监控文件描述符的读写事件
  3. 调度执行:当IO就绪时,恢复对应的协程执行
import asyncio

async def task1():
    print("任务1开始")
    await asyncio.sleep(2)
    print("任务1完成")
    return 1

async def task2():
    print("任务2开始")
    await asyncio.sleep(1)
    print("任务2完成")
    return 2

async def main():
    # 并发执行多个任务
    results = await asyncio.gather(task1(), task2())
    print(f"所有任务完成: {results}")

asyncio.run(main())

异步IO的优势

与传统同步IO对比

同步阻塞方式

import time

def sync_task(name, delay):
    print(f"{name}开始")
    time.sleep(delay)  # 阻塞整个线程
    print(f"{name}完成")

# 顺序执行,总耗时3秒
start = time.time()
sync_task("任务A", 1)
sync_task("任务B", 2)
print(f"总耗时: {time.time() - start}")

异步非阻塞方式

import asyncio
import time

async def async_task(name, delay):
    print(f"{name}开始")
    await asyncio.sleep(delay)  # 不阻塞线程,让出控制权
    print(f"{name}完成")

async def main():
    start = time.time()
    # 并发执行,总耗时约2秒(最长的任务时间)
    await asyncio.gather(
        async_task("任务A", 1),
        async_task("任务B", 2)
    )
    print(f"总耗时: {time.time() - start}")

asyncio.run(main())

实际应用示例:异步网络请求

import aiohttp
import asyncio

async def fetch_url(session, url):
    try:
        async with session.get(url, timeout=10) as response:
            content = await response.text()
            return f"{url}: 成功, 长度: {len(content)}"
    except Exception as e:
        return f"{url}: 失败, 错误: {e}"

async def main():
    urls = [
        "https://httpbin.org/delay/1",
        "https://httpbin.org/delay/2", 
        "https://httpbin.org/delay/1"
    ]
    
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        
        for result in results:
            print(result)

# 运行示例
asyncio.run(main())

关键概念总结

  1. async def:声明异步函数
  2. await:等待异步操作完成,让出控制权
  3. asyncio.run():运行异步程序的主入口
  4. asyncio.create_task():创建并发任务
  5. asyncio.gather():并发运行多个协程
  6. asyncio.sleep():异步延时,不阻塞线程

适用场景

  • 高并发IO密集型应用:如网络服务器、爬虫
  • 需要大量等待的操作:如数据库查询、文件读写
  • 实时数据处理:如WebSocket通信
  • 微服务架构:多个服务间的异步调用

协程和异步IO模型让Python能够高效处理大量并发连接,是现代Python高性能编程的重要工具。

Python中的协程与异步IO模型 协程是Python异步编程的核心概念。让我从基础开始,循序渐进地讲解这个重要的知识点。 什么是协程 协程(Coroutine)是一种比线程更轻量级的并发编程方式。与线程不同,协程的切换由程序自身控制,而不是由操作系统调度。 协程的基本特点 协作式多任务 :协程主动让出执行权,而不是被强制中断 单线程内并发 :多个协程可以在单个线程内交替执行 高效的上下文切换 :协程切换不需要系统调用,开销极小 从生成器到协程 Python的协程是从生成器演化而来的。让我们看一个简单的例子: async/await语法 Python 3.5引入了更清晰的async/await语法: 事件循环(Event Loop) 事件循环是异步编程的核心引擎,负责调度和执行协程。 事件循环的工作原理 维护任务队列 :管理待执行的协程任务 监控IO事件 :通过selector监控文件描述符的读写事件 调度执行 :当IO就绪时,恢复对应的协程执行 异步IO的优势 与传统同步IO对比 同步阻塞方式 : 异步非阻塞方式 : 实际应用示例:异步网络请求 关键概念总结 async def :声明异步函数 await :等待异步操作完成,让出控制权 asyncio.run() :运行异步程序的主入口 asyncio.create_ task() :创建并发任务 asyncio.gather() :并发运行多个协程 asyncio.sleep() :异步延时,不阻塞线程 适用场景 高并发IO密集型应用 :如网络服务器、爬虫 需要大量等待的操作 :如数据库查询、文件读写 实时数据处理 :如WebSocket通信 微服务架构 :多个服务间的异步调用 协程和异步IO模型让Python能够高效处理大量并发连接,是现代Python高性能编程的重要工具。