计算机原理101: 高并发服务
《计算机底层的秘密》读书笔记 + GPT问答整理
I/O 多路复用 + 事件循环 + 多线程
组件 | 职责 |
---|---|
epoll | 高效检测 I/O 准备状态 |
事件循环 | 调度任务、协程、回调执行 |
线程池 | 异步 offload 耗时任务 |
这套模型实现了 高并发、低资源消耗、响应迅速 的目标,是现代服务器架构(如 Nginx、Node.js、Python Tornado)的核心。
一、I/O 多路复用(以 epoll 为代表)
✅ 概念: I/O 多路复用是一种单线程监听多个 I/O 事件的技术,核心是: “一个线程用一个系统调用就能监听多个 socket 的可读/可写状态,而不用为每个连接开一个线程。”
📌 典型代表:
- Linux:epoll
- macOS:kqueue
- Windows:IOCP
- 跨平台:libuv, libevent
1
2
3
4
5
while (true) {
ready_list = epoll_wait(epoll_fd, ...); // 阻塞直到某些 I/O 准备好
for each fd in ready_list:
handle_event(fd);
}
✅ 优点:
- 非阻塞:不会因为单个 I/O 阻塞
- 高并发:1 个线程可管理数万个连接 常用于网络服务器、异步框架(如 Nginx、Redis)
二、事件循环(Event Loop)
事件循环是一个调度机制,用于:
不断轮询任务队列与 I/O 事件,按顺序分发给对应的回调/协程执行。 它是高效异步编程的调度器,常见于:
- 单线程模型中(Node.js, Python asyncio)
- 异步协程系统(Kotlin coroutines, libuv)
1
2
3
while True:
ready_futures = poll_io_events() # 依赖 epoll
run_ready_callbacks(ready_futures) # 恢复协程或执行回调
事件循环中一定不能调用任何阻塞式的接口
三、多线程(Thread Pool)
epoll + 事件循环负责监听和分发; 多线程处理任务,完成后回调通知事件循环;
四、加上协程
协程挂起后并不会阻塞工作线程, 这是协程和利用线程进行阻塞式调用的最大区别。
关键机制 | 作用 |
---|---|
epoll | 单线程管理上万个连接,不阻塞、不分配多线程 |
事件循环 | 作为协调中心,把任务挂起/唤醒 |
协程池 | 成本低,可承载海量任务,不依赖线程数 |
线程池 + 多核并行 | 提高 CPU 利用率,处理计算密集型任务 |
异步挂起 + 恢复 | 遇到 I/O 时不阻塞线程,协程自动让出执行权 |
① 左侧:I/O 来源 + epoll**
- 表示多个客户端或后端服务发来的网络 I/O 请求
- 使用 epoll 来统一监听所有 socket 连接的读写状态
- epoll 本身是非阻塞、事件驱动型的 I/O 多路复用机制
- 可以支持成千上万的连接,用一个线程也能高效处理
✅ 高并发关键点 1: epoll 单线程能管理海量连接,不为每个连接分配线程,极大减少线程资源浪费和上下文切换。
② 中间:事件循环线程
事件循环线程 是 epoll 的使用者:
- 不断调用 epoll_wait 来等待 I/O 事件
- 有事件到来时,会分发给协程系统,让对应任务恢复执行
✅ 高并发关键点 2: 单个事件循环线程可以处理大量并发连接,只要将阻塞任务交由后续的协程/线程即可。
③ 中间偏右:协程池(协程调度器)
每个 I/O 事件会创建一个协程(或者唤醒已有协程)
- 协程是轻量级上下文单元,保留自己的堆栈和执行状态
- 协程被就绪后不会立即运行,而是交给线程池调度执行
📌 协程的优势:
- 成本极低:几十字节至几 KB 内存
- 切换快:仅堆栈保存/恢复,无需系统调用
- 语义清晰:逻辑流程是同步的写法(不像回调地狱)
✅ 高并发关键点 3: 协程的数量可以远大于线程数量(比如 1 万个协程只用几十个线程),避免上下文切换开销。
④ 右侧:线程池 + 多核 CPU 并发执行
- 多个线程从协程队列中取出协程执行
- 每个线程可以并行处理多个协程(通过调度)
- 协程如果再次遇到阻塞(如等 I/O),就会挂起,线程可继续执行别的协程
✅ 高并发关键点 4: 利用线程池并行执行任务,实现 M:N 映射(M个线程调度N个协程),提高 CPU 使用率,避免线程阻塞。