进程与线程:到底有什么区别
一句话区分
进程是资源分配的单位,线程是 CPU 调度的单位。
一个进程可以包含多个线程,它们共享进程的地址空间和资源,但各自拥有独立的栈和寄存器。
内存模型对比
┌─────────── 进程 A ───────────┐
│ 代码段(共享) │
│ 数据段(共享) │
│ 堆(共享) │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │线程1 │ │线程2 │ │线程3 │ │
│ │独立栈│ │独立栈│ │独立栈│ │
│ │独立PC│ │独立PC│ │独立PC│ │
│ └──────┘ └──────┘ └──────┘ │
└──────────────────────────────┘- 共享:代码段、全局变量、堆、打开的文件描述符
- 独立:栈空间、程序计数器、寄存器组、线程 ID
核心区别表
| 维度 | 进程 | 线程 |
|---|---|---|
| 定义 | 程序的一次执行实例 | 进程内的执行流 |
| 资源 | 独立地址空间 | 共享进程资源 |
| 创建开销 | 大(复制页表等) | 小(共享地址空间) |
| 切换开销 | 大(TLB 刷新) | 小(无需切换页表) |
| 通信 | IPC(管道/共享内存/Socket) | 直接读写共享变量 |
| 安全性 | 一个崩溃不影响其他 | 一个崩溃整个进程挂掉 |
什么时候用进程,什么时候用线程
用多进程:
- 需要隔离性(一个任务崩了不能影响其他)
- 典型场景:浏览器(Chrome 每个标签页一个进程)、Nginx worker
用多线程:
- 需要频繁通信、共享大量数据
- 典型场景:Web 服务器处理并发请求、数据库连接池
用协程(补充):
- 大量 I/O 等待、轻量并发
- 典型场景:Go 的 goroutine、Python 的 asyncio
面试高频追问
Q: 线程共享哪些资源,不共享哪些? A: 共享代码段、数据段、堆、文件描述符;不共享栈、寄存器、程序计数器。
Q: 多线程一定比多进程快吗? A: 不一定。CPU 密集型任务在多核下差不多;I/O 密集型线程更优(切换开销小)。Python 因 GIL 限制,CPU 密集型多线程反而更慢。
Q: 死锁的四个必要条件? A: 互斥、持有并等待、不可剥夺、循环等待。破坏任一条件即可预防。