select、poll、epoll是三个常用的I/O复用,之前使用过程中一直没很深入思考,只知道①select有文件描述符上限
②poll是select的改进,去掉了文件描述符上限
③epoll是前两者的增强版,也没有文件描述符上限
直到今天被问了一个问题:poll到底有没有文件描述符上限
首先听到这个问题正常来说的第一反应是:没有
但是!我恰好之前看过些文章,提到poll也有其实也有文件描述符上限,然后也没深入去想,然后就坑了
select
这个问题的关键其实要先理解select关于文件描述符上限的原因
其一:linux系统本身就有文件描述符上限,文件描述符的建立会连带建立很多其它表项,具体可以搜索文件描述符的详解,也就是说文件描述符一定会占用资源,那在有限的硬件条件下,文件描述符必定会有上限,我在ubuntu18.04的虚拟机里通过
cat /proc/sys/fs/file-max //结果95107
得到的结果是95107,也就是系统的文件描述符上限(是所有用户上限的总和)
其二:进程文件描述符上限user limit中nofile的soft limit,实际上这是单个用户的文件描述符上限,通过
ulimit -n //结果1024
得到结果1024
soft limit可以修改,但是不能超过hard limit
ulimit -Hn //结果1048756
这里结果是1048576
然后能看出上限其实有点问题,单进程的hard limit超过了系统上限,这个原因不知道,不过实际上产生进程限制效果的是soft limit,只要注意这个不要修改过头应该就好了
其三:select函数本身限制,主要是头文件中FD_SETSIZE的大小,一般来说是1024,这就限定了select函数中的文件描述符上限,当然可以做修改,但是需要重新编译内核,而且效果由于select的实现机制,会比较差
总结:由于进程的上限会先起作用,所以最后收到限制的原因就是
①进程文件描述符上限
②select中FD_SETSIZE大小
poll
现在问题就来了,既然上面提到了进程会有文件描述符上限,那对poll会起作用吗,我没有尝试,但是应该会起作用,所以很可能在使用poll的时候,会被限制在1024个文件描述符,那poll到底有没有文件描述符上限这个问题,就可以比较全面的回答了
也就是说poll已经可以支持大量的并发连接(我上面都有9w),但是也是由于本身实现的机制,在并发量增大之后,会严重影响效率。
epoll
epoll就是再改进了poll的运行机制,产生的效果就是再大量并发的环境下,也能高效率完成连接的响应,然后很显然epoll的连接数也是有限的,限制的原因就是进程限制和系统限制,在修改这两个限制之后,epoll的连接数就取决于内存大小了
总结
关于文件描述符上限的这个问题,首先就要理解提问者所关注的重点,而且一般来说讨论的是select本身的FD_SETSIZE这个限制,如果是选择题poll和epoll应该没有上限,但如果是问答,最好能讲清楚