STEP_1
阻塞 I/O 的问题不在于"等待"本身,而在于等待时线程被完全占用。现代服务器 90% 以上的时间是在等待 I/O(网络延迟、磁盘读写),真正 CPU 计算只占 10%。这意味着阻塞模型下线程 90% 的时间在空转,CPU 利用率极低。一请求一线程的代价 — PROCESSING
blocking-io.log
// 阻塞 I/O:每个连接一个线程
void handle_client(int sockfd) {
char buf[4096];
// 阻塞:等待数据到达(可能等几百ms)
// 线程在此期间完全挂起,无法处理其他连接
ssize_t n = read(sockfd, buf, sizeof(buf));
if (n > 0) process(buf, n);
}
// Apache 早期模型:prefork
// - 每个请求 fork 一个进程或分配一个线程
// - 1000 并发 = 1000 线程 = ~8GB 栈内存
// - 上下文切换开销极大
// - C10K 问题(1999年):单机 1 万并发不可行阻塞 I/O:传统阻塞 I/O:进程调用 read() 后挂起,直到内核将数据从网卡缓冲区复制到用户空间才返回。整个等待期间线程不可用。1000 个并发连接需要 1000 个线程,内存和切换开销极大。
实时沙盒SANDBOX
NOMINAL
快速场景
手动调节
并发连接数
体现 select vs epoll 的性能差距
1000个
select/poll/epoll 差异不明显
I/O 模型
不同模型的适用场景
epoll 是 Linux 高并发的最优选择
活跃连接比例
同一时刻真正有数据的连接占比
5%
低活跃比(长连接场景),epoll 优势极大