slug
Python 协程
type
Post
status
Published
date
Jun 12, 2026
tags
推荐
文字
summary
category
鱼皮速通
icon
password
核心 analogy
协程 = 能暂停和恢复的函数。普通函数一旦调用就跑到底;协程跑到一半可以主动"让出"控制权(
await),等条件满足再从断点继续。把 event loop 想成一个单线程的调度员:手里攥着一堆协程,谁卡在 I/O(网络、磁盘)就把谁挂起,转去跑别的,等 I/O 好了再回来。所以是 concurrency(并发)不是 parallelism(并行)——始终一个线程,靠"填补等待空隙"提速。
为什么需要它
I/O-bound 场景下,线程大部分时间在 等(等 LLM 返回、等 DB 查询)。多线程能解决但有 GIL + 线程切换开销 + 锁。协程在用户态切换,没有 OS 线程开销,单线程就能扛上万并发连接。
对你做 Agent 直接相关:并行发多个 tool-call、同时打多个 LLM 请求,本质都是用
asyncio 把等待时间复用起来。技术实现
定义与运行
注意:
fetch("a") 本身只是返回一个 coroutine 对象,不执行。必须丢给 event loop(await 它 / 包成 Task / asyncio.run)才真正跑。这是新手最常踩的坑。串行 vs 并发
gather 就是你做 parallel tool dispatch 的核心原语。Task:手动调度
create_task 和 gather 的区别:前者立刻开始执行并返回句柄,后者是"打包 + 等全部完成"。await 能 await 什么
只能 await awaitable:coroutine、Task、Future。底层是对象实现了
__await__。asyncio.sleep 是 awaitable,而 time.sleep 是阻塞调用——在协程里用 time.sleep 会卡死整个 event loop,所有协程一起停。这是另一个高频翻车点。历史包袱(面试可能问)
- Python 3.4:
@asyncio.coroutine+yield from,基于 generator
- Python 3.5+:原生
async/await语法糖,语义上和 generator coroutine 同源(都靠暂停/恢复),但成了独立类型
所以协程本质是 generator 的泛化:generator 用
yield 把值送出去,coroutine 用 await 把控制权让出去。一个线程跑 event loop,轮询式地问 OS "谁的 I/O 好了"。某协程要做 I/O 时,把 fd( file descriptor) 注册给 OS 就让出,线程转身去 resume 其他就绪协程。等待全程由 OS 负责,线程只在彻底没活时才阻塞在
kqueue 上。协程发起网络请求 → OS 给这个连接分配一个 fd(比如 7 号)→ event loop 把"7 号"登记进
kqueue:"盯着 7 号,它可读了喊我" → 线程撒手去跑别人 → 网卡数据到了,内核标记 7 号就绪 → select() 返回"7 号好了" → loop 凭这个号找到对应协程,resume 它。协程要 I/O → 把 fd 注册给 OS → 协程让出 → 线程转去跑别的协程 → OS 处理完 I/O 标记 fd 就绪 → loop 发现后唤醒(resume)对应协程从断点继续。
- Author:盛溪
- URL:https://tangly1024.com/article/Python%20%E5%8D%8F%E7%A8%8B
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!

.jpg?table=block&id=26f7c1d5-a1e9-80d7-a52b-e71bb7079501&t=26f7c1d5-a1e9-80d7-a52b-e71bb7079501)



