Python async与await原理_协程执行机制

4次阅读

async/await 是基于事件循环的用户态协程机制,通过await显式让出控制权,协程对象需await或asyncio.run启动,暂停时保存帧,底层复用生成器机制,事件循环负责i/o轮询与协程调度。

Python async与await原理_协程执行机制

pythonasyncawait 不是线程或进程,而是一种用户态的协作式并发机制——协程(coroutine)。它的核心在于事件循环(Event loop)驱动下的暂停与恢复,不依赖操作系统调度,而是由程序员用 await 显式让出控制权。

async 函数本质是“可等待对象工厂”

async def 定义的函数本身不是协程,而是一个协程函数;调用它返回的是一个协程对象(coroutine Object),这个对象是可等待的(awaitable)。只有真正 await 它时,协程体才开始执行,并在遇到下一个 await 表达式时暂停,把控制权交还给事件循环。

  • 协程对象不可直接调用(coro() 会报错),必须用 await coroasyncio.run(coro) 启动
  • 协程暂停时,不阻塞线程,只是保存当前栈帧(locals、指令指针等)到对象内部,后续可恢复
  • 普通生成器用 yield 暂停,协程用 await 暂停,但底层都基于 Python 的生成器机制(PEP 492 明确复用生成器框架)

await 触发“挂起-调度-恢复”三步动作

await 表达式不是简单等待,而是一套协作协议:

  • 先检查右侧对象是否实现了 __await__ 方法(即是否为 awaitable),如 asyncio.sleep()、其他协程、Future 实例等
  • 调用其 __await__() 得到一个迭代器(通常是生成器),事件循环持续 send(None) 驱动它,直到抛出 StopIteration
  • 若该 awaitable 尚未就绪(如网络未返回),它会向事件循环注册回调,并主动挂起当前协程;待 I/O 完成后,事件循环唤醒它继续执行

事件循环是协程的“中央调度器”

Python 运行时只有一个默认事件循环(主线程中可通过 asyncio.get_event_loop() 获取),它负责:轮询 I/O 状态(如 socket 是否可读)、管理挂起的协程队列、触发回调、分发恢复信号。你写的每个 await,最终都转化为事件循环的一次调度决策。

立即学习Python免费学习笔记(深入)”;

  • asyncio.run() 会创建新循环、运行协程、关闭循环——适合脚本入口
  • 长期服务(如 web 服务器)通常手动维持一个循环,反复调用 loop.run_forever()
  • 协程之间不抢占,谁 await 谁让出,没有锁或竞态问题,但共享变量仍需注意线程安全(因事件循环在单线程内运行)

协程与普通函数的关键区别在控制流语义

同步函数调用是“进→执行→出”,而 async 函数调用是“进→造协程→出”,真正执行发生在 await 时,且可能被多次中断和恢复:

  • 函数内局部变量不会因挂起而丢失,它们绑定在协程对象的闭包
  • 每次 await 后续代码的执行时间不确定,取决于被 await 对象何时就绪
  • 不能在普通函数里 await,也不能在非 async 上下文中使用 await(语法错误)
text=ZqhQzanResources