卡码笔记
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
  • 基础与语法

  • 面向对象

  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

  • 并发与 I/O

    • 互斥锁与自旋锁
    • 说一下select,poll和epoll
      • 简要回答
      • 详细回答
      • 代码示例
      • 知识拓展

# 说一下select,poll和epoll

# 简要回答

select、poll和epoll都是Linux系统中用于I/O多路复用的机制,允许单个线程监视多个文件描述符的就绪状态。

select是最早的实现,有文件描述符数量限制;

poll改进了select的局限性,但性能在大规模连接时仍不理想;

epoll是Linux特有的高性能实现,使用事件驱动模型,适合处理大量并发连接。

# 详细回答

  • 1.select:

最早出现的I/O多路复用机制

使用位图(fd_set)表示文件描述符集合

默认限制为1024个文件描述符(FD_SETSIZE)

每次调用需要重新设置监控集合

采用轮询方式检查就绪状态,时间复杂度O(n)

  • 2.poll:

改进select的文件描述符数量限制

使用pollfd结构数组代替位图

没有最大文件描述符数量的硬性限制

仍然需要遍历所有描述符检查就绪状态

每次调用需要复制整个描述符数组到内核

  • 3.epoll:

Linux特有的高性能I/O多路复用机制

使用事件驱动模型,无需轮询

支持边缘触发(ET)和水平触发(LT)模式

使用红黑树存储监控的描述符,高效管理大量连接

就绪列表直接返回已就绪的描述符,时间复杂度O(1)

使用mmap加速内核与用户空间的数据交换

# 代码示例

// select 示例

fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);

struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;

int ret = select(sockfd+1, &readfds, NULL, NULL, &tv);
if (ret > 0) {
    if (FD_ISSET(sockfd, &readfds)) {
        // 处理可读事件
    }
}
// poll 示例

struct pollfd fds[1];
fds[0].fd = sockfd;
fds[0].events = POLLIN;

int ret = poll(fds, 1, 5000);
if (ret > 0) {
    if (fds[0].revents & POLLIN) {
        // 处理可读事件
    }
}

// epoll 示例

int epfd = epoll_create1(0);
struct epoll_event ev, events[10];
ev.events = EPOLLIN;
ev.data.fd = sockfd;

epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);

int nfds = epoll_wait(epfd, events, 10, 5000);
for (int i = 0; i < nfds; i++) {
    if (events[i].data.fd == sockfd) {
        // 处理可读事件
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 知识拓展

  • 三者性能对比:

连接数少时,三者性能差异不大

连接数超过1000时,select/poll性能线性下降,epoll性能基本不受连接数影响

  • 适用场景:

select/poll: 跨平台程序,连接数少

epoll: Linux平台高并发服务

  • 水平触发(LT)和边缘触发(ET)

ET: 只在状态变化时通知一次,必须一次性处理完所有数据

LT: 只要满足条件就持续通知,可以分多次处理

  • 知识图解

image

  • 面试官可能追问

Q1.为什么epoll比select/poll更高效?

epoll使用事件驱动而非轮询,只关注活跃连接

epoll使用红黑树管理描述符,查找效率高

epoll_wait直接返回就绪列表,无需遍历所有连接

内核与用户空间共享内存,减少数据拷贝

Q2.epoll的LT和ET模式有什么区别?如何选择?

LT(水平触发): 只要fd就绪就会不断通知

ET(边缘触发): 只在fd状态变化时通知一次

ET效率更高但编程更复杂,需要一次处理完所有数据

默认使用LT,高性能场景使用ET

Q3.epoll是如何实现高性能的?

使用红黑树存储监控的fd,插入删除效率高

就绪列表直接返回活跃fd,无需遍历

使用mmap共享内存减少内核与用户空间数据拷贝

回调机制避免轮询

Q4.select的1024限制可以修改吗?

可以修改FD_SETSIZE宏并重新编译程序

但不推荐,因为内核可能有自己的限制

需要大文件描述符数量时应改用poll/epoll

Last Updated: 3/10/2026, 6:08:48 PM

← 互斥锁与自旋锁

评论

验证登录状态...

侧边栏
夜间
卡码简历
代码随想录
卡码投递表🔥
2026群
添加客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记
鼓励/支持/赞赏Carl
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪