五种并发/异步模型整理
1. 线程(Thread)
- 理解:来一个任务开一个线程,独立运行。
- 特点:抢占式调度,内核管理,阻塞不影响主线程。
- 优点:简单、逻辑像同步一样顺。
- 缺点:重、耗资源、多锁容易死锁。
- 场景:普通后台任务、少量并发。
2. 协程(Coroutine)
- 理解 :多个函数协同运行、互相让出、交替前进,一起推进状态。
- 特点:用户态切换,不阻塞线程,遇到等待主动 yield。
- 优点:极轻量、高并发、无内核开销。
- 缺点:需要手动或调度器切换。
- 场景:高并发网络、游戏逻辑、生产者消费者。
3. IO 多路复用(epoll / select / poll)
- 理解 :一个线程等待一堆 socket,哪个就绪处理哪个。
- 底层 :依赖网卡中断,内核标记就绪,epoll 只负责查询就绪集合。
- 优点:超高并发、极省资源。
- 缺点:编码是事件驱动,逻辑较绕。
- 场景:Nginx、Redis、高并发服务器。
4. 异步 IO(AIO)
- 理解 :提交读写请求就立刻返回,完成后系统主动通知。
- 底层 :完全依赖磁盘/网卡硬件中断。
- 优点:真正不阻塞,不轮询。
- 缺点:API 复杂,系统兼容性一般。
- 场景:高性能文件读写、存储系统。
5. 信号 + 回调
- 理解:内核通过信号通知进程,进程执行回调。
- 底层 :来自中断/异常的封装。
- 为什么不稳定 :
- 同一信号多次会合并丢失
- 没有队列,不适合高频
- 回调上下文不安全
- 场景:简单通知、超时、程序退出。
总结
- 线程:开小弟干活
- 协程:互相配合协同跑
- epoll:等一堆 IO 就绪
- AIO:提交完等中断通知
- 信号:中断封装的简单通知,但会丢、不稳定
5 种并发/异步模型 · 极简对比表
| 方式 | 核心一句话 | 底层靠什么 | 优点 | 缺点 | 典型场景 |
|---|---|---|---|---|---|
| 线程 | 一人一事,阻塞也各玩各的 | 内核调度 | 简单直观 | 重、耗资源、易死锁 | 普通后台任务、低并发 |
| 协程 | 多函数协同交替,一起推进 | 用户态切换 | 极轻量、高并发 | 需手动/调度器切换 | 高并发网络、游戏 |
| IO多路复用(epoll) | 一个线程等一堆IO,就绪才处理 | 网卡中断+内核就绪队列 | 超高并发、省资源 | 逻辑碎片化、事件驱动 | Nginx、Redis、高并发网络通信服务 |
| 异步IO(AIO) | 提交IO就走,完成中断通知 | 磁盘/网卡硬件中断 | 真正不阻塞 | API复杂、兼容性一般 | 高性能文件/存储读写 |
| 信号+回调 | 中断封装的简单通知 | 中断/异常 | 轻、简单 | 会丢信号、不安全、不可靠 | 闹钟、程序退出、简单通知 |
超短记忆版
- 线程:多个人独立干活
- 协程:互相让位协同干活
- epoll:一个人盯一堆事件
- AIO:提交完等硬件喊完成
- 信号:简易通知,但会丢