【128期】一道搜狗面试题:IO多路复用中select、poll、epoll之间的区别
程序员的成长之路
共 5617字,需浏览 12分钟
·
2021-02-02 00:19
阅读本文大概需要 8.5 分钟。
(1)select==>时间复杂度O(n)
(2)poll==>时间复杂度O(n)
(3)epoll==>时间复杂度O(1)
select:
poll:
大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
epoll:
epoll为什么要有EPOLLET触发模式?
没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口); 效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。 内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。
select、poll、epoll 区别总结:
1、支持一个进程所能打开的最大连接数
select
poll
epoll
2、FD剧增后带来的IO效率问题
select
poll
epoll
3、 消息传递方式
select
poll
epoll
总结:
1、select实现
使用copy_from_user从用户空间拷贝fd_set到内核空间 注册回调函数__pollwait 遍历所有fd,调用其对应的poll方法(对于socket,这个poll方法是sock_poll,sock_poll根据情况会调用到tcp_poll,udp_poll或者datagram_poll) -以tcp_poll为例,其核心实现就是__pollwait,也就是上面注册的回调函数。 __pollwait的主要工作就是把current(当前进程)挂到设备的等待队列中,不同的设备有不同的等待队列,对于tcp_poll来说,其等待队列是sk->sk_sleep(注意把进程挂到等待队列中并不代表进程已经睡眠了)。在设备收到一条消息(网络设备)或填写完文件数据(磁盘设备)后,会唤醒设备等待队列上睡眠的进程,这时current便被唤醒了。 poll方法返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值。 如果遍历完所有的fd,还没有返回一个可读写的mask掩码,则会调用schedule_timeout是调用select的进程(也就是current)进入睡眠。当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的进程。如果超过一定的超时时间(schedule_timeout指定),还是没人唤醒,则调用select的进程会重新被唤醒获得CPU,进而重新遍历fd,判断有没有就绪的fd。 把fd_set从内核空间拷贝到用户空间。
总结:
每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大 同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大 select支持的文件描述符数量太小了,默认是1024
2、poll实现
3、epoll
总结:
推荐阅读:
【127期】面试官:你说使用过ZooKeeper,那来说说他的基本原理吧
【125期】举例说明消息队列应用场景及ActiveMQ、RocketMQ、Kafka等的对比
微信扫描二维码,关注我的公众号
朕已阅
评论