Python协程函数

1. 协程函数的定义

在 Python 中,协程函数通过 async def 语法定义,它是一种特殊的函数类型,与普通函数不同的是:

  • 调用协程函数不会立即执行其内部代码,而是返回一个协程对象
  • 协程函数内部可以使用 await 关键字暂停执行,等待其他协程完成
 
# 定义一个简单的协程函数
async def fetch_data(url):
    # 模拟网络请求
    await asyncio.sleep(1)
    return {"data": "example", "url": url}
 

2. 协程函数的调用与执行

协程函数的调用分为三个核心步骤:
  1. 创建协程对象:调用协程函数得到协程对象
  2. 调度协程执行:将协程对象提交给事件循环
  3. 等待结果返回:使用 await 或 asyncio.run() 获取结果
 
import asyncio

async def fetch_data(url):
    await asyncio.sleep(1)
    return {"data": "example", "url": url}

# 错误调用方式(仅创建协程对象,不执行)
coro = fetch_data("https://example.com")  # 不会执行协程内部代码

# 正确调用方式1:在另一个协程中使用 await
async def main():
    result = await fetch_data("https://example.com")
    print(result)

# 正确调用方式2:使用 asyncio.run() 运行顶层协程
asyncio.run(fetch_data("https://example.com"))
 

3. 协程函数的核心机制

3.1 await 关键字
await 是协程的核心机制,它的作用是:

  • 暂停当前协程的执行
  • 将控制权交回事件循环
  • 等待目标协程完成并返回结果
  • 恢复当前协程的执行

async def task1():
    print("Task 1 started")
    await asyncio.sleep(2)  # 暂停执行2秒
    print("Task 1 finished")

async def task2():
    print("Task 2 started")
    await asyncio.sleep(1)  # 暂停执行1秒
    print("Task 2 finished")

async def main():
    await task1()  # 顺序执行:等待task1完成后才执行task2
    await task2()
 
3.2 并发执行协程
使用 asyncio.gather() 可以并发执行多个协程:
 
async def main():
    # 并发执行两个协程
    results = await asyncio.gather(
        fetch_data("https://url1.com"),
        fetch_data("https://url2.com")
    )
    print(results)  # 同时获取两个协程的结果
 
3.3 创建后台任务
使用 asyncio.create_task() 创建可独立运行的任务:
async def background_task():
    await asyncio.sleep(3)
    print("Background task completed")

async def main():
    # 创建后台任务并立即执行
    task = asyncio.create_task(background_task())
    print("Main function continues...")
    await task  # 等待后台任务完成
 

4. 协程的生命周期管理

async def long_running_task():
    try:
        print("Task started")
        await asyncio.sleep(10)
        print("Task completed")
    except asyncio.CancelledError:
        print("Task cancelled")

async def main():
    task = asyncio.create_task(long_running_task())
    await asyncio.sleep(2)
    
    # 取消任务
    task.cancel()
    
    try:
        await task  # 等待任务结束(可能抛出 CancelledError)
    except asyncio.CancelledError:
        print("Task was cancelled")
 

5. 协程的使用场景

5.1 I/O 密集型应用
  • 网络爬虫:并发请求多个 URL
  • API 调用:同时调用多个微服务
  • 数据库操作:并发执行多个查询
 
async def fetch_urls(urls):
    async with aiohttp.ClientSession() as session:  # 使用 aiohttp 库
        tasks = [fetch(session, url) for url in urls]
        return await asyncio.gather(*tasks)

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()
 
5.2 实时数据处理
  • WebSocket 服务器:同时处理多个客户端连接
  • 消息队列消费者:并发处理多个消息
import websockets

async def handler(websocket):
    async for message in websocket:
        await process_message(message)

async def main():
    async with websockets.serve(handler, "localhost", 8765):
        await asyncio.Future()  # 保持服务器运行
 
5.3 异步任务编排
  • 定时任务:使用 asyncio.sleep() 实现异步定时器
  • 任务流水线:一个任务的输出作为另一个任务的输入
 
 
async def producer(queue):
    for i in range(5):
        await queue.put(i)
        await asyncio.sleep(1)

async def consumer(queue):
    while True:
        item = await queue.get()
        print(f"Processing: {item}")
        queue.task_done()
 

6. 协程与多线程 / 多进程的对比

特性协程多线程多进程
并发方式 单线程,协作式调度 内核级线程调度 多个进程
创建成本 极低(微秒级) 中等(毫秒级) 高(毫秒级)
切换成本 极低(纳秒级) 较高(微秒级) 高(毫秒级)
CPU 利用率 适合 I/O 密集型 适合 I/O 密集型 适合 CPU 密集型
共享资源 共享全局变量 共享全局变量 不共享
复杂度 中等(需理解异步) 高(锁管理) 高(进程间通信)

7. 最佳实践与注意事项

  1. 避免阻塞事件循环:在协程中避免执行耗时的同步操作,否则会阻塞所有协程
# 错误做法:在协程中执行耗时同步操作
async def bad_example():
    time.sleep(5)  # 阻塞整个事件循环
    
# 正确做法:使用异步版本或运行在单独线程
async def good_example():
    await asyncio.sleep(5)  # 正确的异步睡眠
 

  1. 异常处理:协程中的未捕获异常可能导致整个应用崩溃
 
 
async def task():
    raise ValueError("Oops!")

async def main():
    try:
        await task()
    except ValueError as e:
        print(f"Caught error: {e}")
 

  1. 资源管理:使用 async with 和 async for 管理异步资源
async def process_file():
    async with aiofiles.open("data.txt", "r") as f:  # 使用 aiofiles 库
        async for line in f:
            await process_line(line)
 

8. 相关库与工具

  1. asyncio:Python 标准库,提供协程、事件循环、任务管理等核心功能
  2. aiohttp:异步 HTTP 客户端 / 服务器库,用于网络请求
  3. aioredis:异步 Redis 客户端,用于缓存和消息队列
  4. aiofiles:异步文件操作库,用于文件 I/O
  5. websockets:异步 WebSocket 库,用于实时通信

通过掌握协程函数的定义、调用和应用场景,你可以构建高性能、高并发的 Python 应用程序,尤其适合处理大
posted @ 2025-06-22 16:07  郭慕荣  阅读(83)  评论(0)    收藏  举报