面试题答案
一键面试处理大量并发连接的方式
- select:select 会监控一组文件描述符(fd_set),当调用 select 时,内核会遍历这组文件描述符,检查哪些描述符上有事件发生(可读、可写或异常)。如果有事件发生,select 返回,应用程序需要遍历整个文件描述符集合来确定具体是哪个描述符发生了事件,然后进行相应处理。
- poll:poll 和 select 类似,也是监控一组文件描述符。poll 使用 pollfd 结构体数组来存储需要监控的文件描述符及其事件。同样,内核遍历这组描述符,当有事件发生时,poll 返回,应用程序同样需要遍历数组来找到发生事件的描述符并处理。
- epoll:epoll 采用事件驱动机制。首先通过 epoll_create 创建一个 epoll 实例,然后使用 epoll_ctl 向这个实例中添加、修改或删除要监控的文件描述符及其感兴趣的事件。当有事件发生时,epoll_wait 会返回发生事件的文件描述符列表,应用程序直接处理这些返回的描述符即可,无需遍历整个监控集合。
异同点
- 相同点
- 都是 IO 多路复用技术,目的是为了在单线程中高效处理多个并发的 I/O 事件,提高程序的并发性能。
- 都可以对多个文件描述符进行监控,等待这些文件描述符上的 I/O 事件发生。
- 不同点
- 数据结构:
- select:使用 fd_set 结构体来存储文件描述符集合,这个集合大小是固定的(通常是 1024),限制了可监控的文件描述符数量。
- poll:使用 pollfd 结构体数组,理论上对监控的文件描述符数量没有限制。
- epoll:通过 epoll_create 创建的 epoll 实例内部使用红黑树来管理监控的文件描述符,并且使用链表来存储发生事件的文件描述符,这种数据结构使得 epoll 在处理大量文件描述符时效率更高。
- 工作模式:
- select 和 poll:都是水平触发(LT)模式,即只要文件描述符对应的缓冲区还有数据可读或可写,就会一直通知应用程序。
- epoll:支持水平触发(LT)和边缘触发(ET)两种模式。边缘触发模式下,只有当文件描述符状态发生变化(例如新数据到达)时才会通知应用程序,相比水平触发模式可以减少不必要的系统调用,提高效率,但编程复杂度也更高。
- 效率:
- select:每次调用都需要将整个文件描述符集合从用户态拷贝到内核态,并且遍历整个集合来检查事件,时间复杂度为 O(n),在处理大量文件描述符时效率较低。
- poll:与 select 类似,每次调用也需要遍历整个文件描述符数组,时间复杂度也是 O(n),不过由于 pollfd 结构体更灵活,在处理大量文件描述符时性能略优于 select。
- epoll:epoll 在内核中维护了监控的文件描述符集合,只需要在添加、修改或删除描述符时进行少量的数据拷贝,并且 epoll_wait 返回时直接给出发生事件的描述符列表,时间复杂度为 O(1),在处理大量并发连接时效率更高。
- 数据结构: