05什么是协程,它和线程、进程的核心区别是什么?
文章目录
问题: 什么是协程,它和线程、进程的核心区别是什么?
👇 点击展开/折叠 面试背诵模板(建议先背这个)
调度机制的底层差异
| 维度 | 进程 | 线程 | 协程 |
|---|---|---|---|
| 调度者 | 操作系统内核 | 操作系统内核 | 程序自身(事件循环) |
| 调度方式 | 抢占式(时间片轮转) | 抢占式(时间片轮转) | 协作式(主动await让出) |
| 切换时机 | 时间片耗尽/中断 | 时间片耗尽/中断 | I/O等待或主动await |
| 切换是否涉及系统调用 | ✅ 是(陷入内核) | ✅ 是(陷入内核) | ❌ 否(纯用户态) |
内存与切换开销对比
1 | # 协程的极简切换示例(无锁、无系统调用) |
| 对比项 | 进程切换 | 线程切换 | 协程切换 |
|---|---|---|---|
| 保存上下文 | 页表、内存映射、寄存器、栈 | 寄存器、栈、PC | 仅寄存器、栈(极简) |
| 内核态切换 | 有(系统调用) | 有(系统调用) | 无 |
| 典型耗时 | ~微秒级(1-10μs) | ~微秒级(0.5-1μs) | ~纳秒级(数十ns) |
| 内存占用 | ~MB级(独立空间) | ~数MB(栈默认1-8MB) | ~数KB(栈动态增长) |
协程的核心特性与局限
特性(优势):
- 极高并发:单线程可轻松管理数万个协程,而线程受系统资源限制(通常数千)。
- 无锁编程:单线程内无需考虑竞态条件,天然避免死锁和数据竞争(前提是不混用多线程)。
- 资源高效:创建和销毁开销极低,适合高并发I/O场景(如Web服务器、爬虫)。
局限(劣势):
- 无法利用多核:协程本身在单线程内运行,不能并行计算。若需多核,需配合多进程(如
ProcessPoolExecutor)。 - 阻塞操作致命:协程内若执行同步阻塞I/O(如
time.sleep、requests.get)会阻塞整个事件循环,必须使用异步版本(如asyncio.sleep、aiohttp)。 - 侵入性强:所有依赖库必须支持异步(async/await),历史遗留同步代码难以迁移。
Python协程的发展简史
| 版本 | 实现方式 | 说明 |
|---|---|---|
| Python 2.5 | yield 生成器协程 |
基于生成器的半协程,功能有限 |
| Python 3.4 | @asyncio.coroutine + yield from |
asyncio 标准库引入,语法较繁琐 |
| Python 3.5 | async/await 语法 |
原生协程支持,取代生成器协程(推荐) |
| Python 3.7+ | asyncio.run() |
简化事件循环启动,统一API |
三者的选型速查口诀(拓展补充)
计算密集用进程,I/O密集用线程,海量连接用协程。
协程是线程的“升级版”——在I/O密集型高并发场景下,协程能以极低资源支撑远超线程数量的并发连接,但需接受异步编程范式的改造。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 LGQ的博客!