面试题答案
一键面试select
- 工作原理:
- select函数有三个参数,分别是读文件描述符集合(
readfds
)、写文件描述符集合(writefds
)、异常文件描述符集合(exceptfds
),以及一个超时时间(timeout
)。 - 它会轮询检查这三个集合中的文件描述符,当其中某个文件描述符就绪(可读、可写或有异常)时,select函数返回。
- 调用者需要遍历这些集合,以确定哪些文件描述符已经就绪。
- select函数有三个参数,分别是读文件描述符集合(
- 优点:
- 几乎所有主流操作系统都支持,具有较好的跨平台性。
- 缺点:
- 单个进程能够监视的文件描述符的数量存在最大限制,在Linux上通常为1024,可以通过修改宏定义或编译时参数提高,但有一定限度。
- 每次调用select,都需要将文件描述符集合从用户态拷贝到内核态,开销较大。
- 当有大量文件描述符时,轮询检查每个文件描述符是否就绪效率低下。
poll
- 工作原理:
- poll使用一个
pollfd
结构体数组来存储文件描述符及其感兴趣的事件(读、写、异常等)。 - 内核同样会轮询检查这些文件描述符,当有文件描述符就绪时,
poll
函数返回。 - 调用者需要遍历
pollfd
数组来找出就绪的文件描述符。
- poll使用一个
- 优点:
- 没有文件描述符数量的限制,理论上可以处理任意数量的文件描述符。
- 相比
select
,从用户态到内核态的数据拷贝量较小,因为poll
使用结构体数组,而不是像select
那样使用位图。
- 缺点:
- 本质上还是轮询方式,当文件描述符数量众多时,性能会急剧下降。
- 每次调用
poll
,同样需要将数据从用户态拷贝到内核态,开销依然存在。
epoll
- 工作原理:
- epoll_create:首先通过
epoll_create
函数创建一个epoll
实例,在内核中开辟一块空间用于存储需要监听的文件描述符。 - epoll_ctl:使用
epoll_ctl
函数向epoll
实例中添加、修改或删除要监听的文件描述符及其感兴趣的事件。 - epoll_wait:
epoll_wait
函数等待事件发生。当有事件发生时,epoll
会将就绪的文件描述符复制到用户态提供的数组中返回给用户,用户无需遍历所有监听的文件描述符,直接处理返回的就绪文件描述符即可。 epoll
采用回调机制,当文件描述符状态发生变化时,内核会将其加入到就绪队列中,而不是像select
和poll
那样轮询检查所有文件描述符。
- epoll_create:首先通过
- 优点:
- 支持大量并发连接,能处理大量文件描述符,没有文件描述符数量的限制。
- 效率高,采用回调机制,只有文件描述符状态发生变化时才会通知,而不是轮询检查所有文件描述符,减少了不必要的开销。
- 每次调用
epoll_wait
时,只需要将就绪的文件描述符从内核态拷贝到用户态,而不是像select
和poll
那样将所有文件描述符都拷贝到内核态并再拷贝回来,进一步提高了效率。
- 缺点:
- 只在Linux系统下支持,跨平台性不如
select
。 - 实现相对复杂,需要更多的代码和知识来正确使用。
- 只在Linux系统下支持,跨平台性不如
优缺点比较总结
- 可处理文件描述符数量:
select
有数量限制,通常为1024。poll
理论上无限制。epoll
同样无限制,且在处理大量文件描述符时性能更优。
- 性能:
select
和poll
在文件描述符数量较多时,由于轮询方式,性能较低。epoll
采用回调机制,性能更高,尤其适用于高并发场景。
- 跨平台性:
select
跨平台性最好,几乎所有主流操作系统都支持。poll
也有较好的跨平台性,但略逊于select
。epoll
仅在Linux系统下支持,跨平台性差。