进程、线程、协程是后端面试的高频考点,也是理解并发编程的基础。这篇文章把三者的区别、原理和面试答题思路一次讲清楚。
进程(Process)
操作系统分配资源的基本单位。每个进程有独立的内存空间(代码段、数据段、堆、栈),进程之间互相隔离。
- 创建开销大(要分配独立内存、初始化各种资源)
- 崩了不影响其他进程
- 通信麻烦,要走 IPC(管道、消息队列、共享内存等)
类比: 每个进程是一个独立的工厂,有自己的厂房和设备。
线程(Thread)
CPU 调度的基本单位。线程是进程内的执行单元,同一进程的线程共享内存空间(堆、全局变量),但每个线程有自己的栈和寄存器。
- 创建开销比进程小
- 共享内存,通信方便,但要处理并发安全(锁、同步)
- 一个线程崩了可能拖垮整个进程
类比: 同一工厂里的多个工人,共用厂房和设备,但各自有自己的工作台。
协程(Coroutine)
用户态的轻量级”线程”,由程序自己调度,不依赖操作系统。协程在单线程内运行,遇到 I/O 等待时主动让出 CPU,切换到其他协程继续跑。
- 创建和切换开销极小(不涉及内核态切换)
- 没有线程安全问题(单线程内跑)
- 适合 I/O 密集型场景(网络请求、数据库查询)
- 不适合 CPU 密集型(单线程跑满 CPU,其他协程都卡着)
类比: 一个工人同时处理多件事,做 A 的时候等材料,就先去做 B,材料到了再回来继续 A。
三者对比
| 进程 | 线程 | 协程 | |
|---|---|---|---|
| 调度者 | 操作系统 | 操作系统 | 用户程序 |
| 内存 | 独立 | 共享(同进程) | 共享(同线程) |
| 切换开销 | 大 | 中 | 极小 |
| 并发安全 | 天然隔离 | 需要加锁 | 单线程无竞争 |
| 适合场景 | 隔离性要求高 | CPU 密集 + 多核 | I/O 密集 |
面试常问的延伸点
为什么协程切换比线程快?
线程切换需要进入内核态,保存/恢复寄存器、切换页表等,开销在微秒级。协程切换在用户态完成,只需保存少量寄存器,开销在纳秒级。
Go 的 goroutine 是协程吗?
是协程的变体,但 Go runtime 会把 goroutine 调度到多个系统线程上跑(M:N 模型),所以能利用多核,比传统协程更强。
Python 的 asyncio 是协程吗?
是,基于事件循环的协程,单线程,遇到 await 就切换。适合网络 I/O,但 CPU 密集任务还是要用多进程(绕过 GIL)。
理解这三者的本质区别,再去看并发编程、异步框架、Go/Python 的并发模型,会清晰很多。