计算机原理101:高并发服务

Posted by FridayLi on May 1, 2025

计算机原理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 使用率,避免线程阻塞。