协程与事件循环

协程与事件循环

协程

协程是一种用户态的轻量级线程,允许在多个任务间高效的切换,而无需依赖操作系统的线程调度。

特点

  • 协作式多任务:协程主动让出执行权(通过 yieldawait),而非被操作系统调度(强制中断——抢占式)。
  • 状态保存:协程的状态保存在协程的栈中,协程切换时保存上下文(如局部变量、执行位置), 恢复时从中断处继续。
  • 性能提升:协程相比线程,在切换消耗上性能提升。

缺点

  • 需要在代码中显式调用,且需要手动维护协程状态,容易出错。
  • 调试困难,调试协程时,需要手动跟踪协程状态,且协程切换时,会中断程序执行,需要手动恢复。

协程实现

协程库中有很多实现的方式,详情请参考协程相关文档。

import asyncio

async def my_coroutine():
    print("协程开始")
    await asyncio.sleep(1)  # 模拟异步操作
    print("协程结束")

# 运行协程
asyncio.run(my_coroutine())

协程在运行需要使用 asyncio.run() 函数,该函数会创建一个事件循环,并运行协程。

事件循环

事件循环是协程的运行环境,它负责管理协程的生命周期,包括协程的创建、调度和销毁。

特点

  • 单线程调度器:在单线程中轮询任务队列,决定何时执行哪个任务。
  • 事件驱动:监听外部事件(如IO操作完成、定时器到期等),并根据事件触发相应的任务(如回调或协程恢复)。
  • 非阻塞执行:通过异步IO和任务切换,避免因等待资源而阻塞主线程。

工作原理图

启动循环
检查任务队列
执行就绪任务
监听事件
触发回调
循环重复

协程注意事项

  • 1. 禁止直接调用协程函数
    错误示例: coroutine() (未 await)
    正确示例: await coroutine()asyncio.create_task(coroutine())
  • 2. 协程函数中不能包含同步代码
    协程中不能包含同步代码,因为协程是运行在单线程中的,如果协程中包含同步代码,则协程会阻塞整个线程,导致其他协程无法运行。
    错误示例:
    async def coroutine(): 
        print("协程开始")
        time.sleep(5)          # 错误示例:同步代码
        print("协程结束")
    
    正确示例:
    async def coroutine(): 
        print("协程开始")
        await time.sleep(5)    # 改成异步代码(对于不可避免的同步操作,可使用 run_in_executor 重构)
        print("协程结束")
    
  • 3. 资源释放
    事件循环在使用 loop.close() 关闭时,会自动释放所有资源。
  • 4. 协程的Debug
    协程因为难调试的特点,所以在调试时,通过环境变量设置 PYTHONASYNCIODEBUG=1 来开启协程调试。

你可能感兴趣的:(python)