select
- select 最多只能监听1024个文件描述符,且这1024个文件描述符的最大值不能超过1023,这是因为selset使用的fd_set结构体。fd_set结构体内容如下:
__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
typedef long int __fd_mask;
#define __FD_SETSIZE 1024
#define __NFDBITS (8 * (int) sizeof (__fd_mask))
long int fds_bits[1024 / sizeof(long int)]
fd_set直接看成一个数组,以32位机为例,就相当于一个长度为(1024 / 32)的long int数组,里面使用一位监听一个文件描述符,故其最多只可监听1024个文件描述符,且最大文件描述符为1023。
- select每次监听前都要为想要构造想要监听的fd_set,因为select是通过你所传递进去的文件fd_set返回的,在内核中会修改fd_set表中的内容。这是因为在内核中会先将用户空间定义的fd_set拷贝到内核空间,在内核空间会对文件描述符进行监听,在数据没有准备好的时候,进程会放弃cpu进入到休眠态,当被唤醒后会再次遍历拷贝到内核中的fd_set,找到对应的就绪文件描述符,将对应位置一,最后再将将内核中的fd_set拷贝到用户空间,用户拿到的fd_set是已经就绪的文件描述符表,不一定是原来的表,因此每次在监听前都要重新构造fd_set,所以效率低。
- 当select对应的进程休眠时,如果对应的文件描述符准备好了,还要再次遍历整个文件描述符的表,将对应的位置一,不能直接返回准备好的文件描述符表,因此效率低。
poll
- poll监听的文件描述符没有个数限制,因为poll使用的是结构体指针,因此没有描述符的个数限制。
struct pollfd {
int fd;
short events;
short revents;
};
- poll表不会被清空,不需要反复构造,效率高。
- 当poll对应的进程休眠的时候,如果有文件描述符的数据准备好了,还需要再次遍历文件描述符,效率低。
epoll
- epoll监听的文件描述符没有个数限制,epoll使用的是红黑树。
- epoll表不会被清空,不需要反复构造,效率高。
- 当epoll对应的进程休眠的时候,如果有文件描述符的数据准备好了,不需要遍历文件描述符,它可以直接拿到准备好的文件描述符。效率高。
注意:
select、poll和epoll在驱动中使用的都是.poll,它们的不同都在VFS中。