面经
后端开发面经问题
Q:请描述 select、poll、epoll 这三种IO多路复用技术的执行原理
IO 多路复用(IO Multiplexing)是一种在单个线程中同时监控多个文件描述符(如网络套接字、文件等)的方法。当其中任何一个文件描述符变得可读、可写或发生错误时,程序可以进行相应的处理。IO 多路复用的主要目的是提高系统的并发处理能力,尤其是在网络编程中。
常见的 IO 多路复用机制
select:最早的 IO 多路复用机制,支持监控多个文件描述符,但存在文件描述符数量限制和性能问题。
poll:类似于 select,但没有文件描述符数量限制,性能稍有改善。
epoll:Linux 特有的 IO 多路复用机制,性能优于 select 和 poll,适用于大规模并发连接。
kqueue:FreeBSD 和 macOS 上的 IO 多路复用机制,类似于 epoll。- A:select、poll、epoll 都是 IO 多路复用的机制,都是通过一个线程来监听多个文件描述符的可读、可写、异常等事件。select 是最早的实现,poll 是对 select 的改进,epoll 是对 poll 的改进。
- select:select 是通过一个 fd_set 来存储文件描述符,通过 select 函数来监听这些文件描述符的事件。
- 将当前进程的所有文件描述符,一次性从用户态拷贝到内核态。
- 在内核中快速的无差别遍历每一个fd,判断是否有数据到达
- 将所有的fd状态从内核态拷贝到用户态,并返回已就绪遇到fd数量
- 在用户态遍历判断具体是哪个fd已经就绪,然后再进行对应的事件处理;
select 的缺点是,每次调用 select 函数都需要将 fd_set 从用户态拷贝到内核态,然后内核再将结果拷贝到用户态,这样的开销比较大;而且文件描述符表有大小限制,一般是 1024 个;遍历的轮询时间复杂度是 O(n)。
- poll:poll 是通过一个 pollfd 结构体来存储文件描述符,通过 poll 函数来监听这些文件描述符的事件。网卡 -> 内核环形缓冲区 -> 数据接受队列,谁的数据接受队列有数据,revents就置位为1;遍历fd,被检测到之后重新恢复为0。
1
2
3
4
5struct pollfd {
int fd; // 文件描述符
short events; // 事件类型
short revents; // 返回的事件类型
};
具体的工作流程和原理和 select 类似,只是 poll 使用 pollfd 结构体来存储文件描述符,poll 函数来监听文件描述符的事件。
poll 的优点是,pollfd 结构体的大小是固定的,不需要像 select 一样需要重新设置 fd_set 的大小,能承受更高的并发。但是 poll 也有一个缺点,就是 pollfd 结构体是线性存储的,当文件描述符比较多的时候,查询效率会比较低。其他轮询和频繁切换拷贝的问题和 select 一样。 - epoll:epoll 是通过一个 epoll_event 结构体来存储文件描述符,通过 epoll_ctl 函数来注册文件描述符,通过 epoll_wait 函数来监听这些文件描述符的事件。
- 在epoll_ctl()函数中,为每个文件描述符都指定了回调函数,基于回调函数把就绪事件放到就绪队列中,因此,把时间复杂度从O(n)降到了O(1)。
- 只需要在 epoll_ctl()时传递一次文件描述符,epoll_wait()不需要再次传递文件描述符。
- epoll 基于红黑树+双链表存事件,没有最大连接数的限制,不存在 C10K 问题(C10K 全称是 “Concurrent 10,000 connections problem”。它指的是如何在一台服务器上同时处理一万个并发连接的问题。这个问题的提出是为了应对高并发网络服务器的性能挑战)。
- 注意: epoll 没有使用MMAP零拷贝技术(详见RocketMQ 为什么性能不如 Kafka ?)
epoll 的优点是,epoll_event 结构体是一个链表结构,可以快速的查询到需要的文件描述符,而且 epoll_wait 函数是一个阻塞函数,只有当有文件描述符的事件发生的时候,才会返回,不需要像 select 和 poll 一样需要轮询查询。epoll 的缺点是,epoll_event 结构体的大小是动态的,需要动态的分配内存,这样会增加内存的开销。
WXG面经
推荐公司
自动驾驶
- 文远知行
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.