《技术之瞳》- 操作系统 - 习题 2.42

关于linux的I/O复用接口select和epoll,下列说法错误的是()

A、 select调用时会进行线性遍历,epoll采用回调函数机制,不需要线性遍历
B、 select的最大连接数为FD_SETSIZE
C、 select较适合于有大量并发连接,且活跃链接较多的场景
D、 epoll较适用于有大量并发连接,但活跃连接不多的场景
E、 epoll的效率不随FD数目增加而线性下降
F、 epoll通过共享存储实现内核和用户的数据交互


select 和 epoll效率差异的原因:select采用轮询方式处理连接,epoll是触发式处理连接。

什么是轮询?
假如你有个快递要到了,但是不知道多久到,你就隔一分钟给快递员打个电话问到了没有,显然这是比较浪费时间(时间片)和消耗钱财(资源)的事情,而且也是处理事情最笨的办法。

什么是触发式处理连接?
你知道你的快递要到了,你也知道到了之后会给你打电话,在这段时间你可以睡觉(不占用时间片),等到他给你打电话(通知)的时候再去拿快递,这就叫触发式处理连接。

Select:
1.Socket数量限制:该限制可操作的Socket数由FD_SETSIZE决定,内核默认32*32=1024.
2.操作限制:通过遍历FD_SETSIZE(1024)个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。

Epoll
1.Socket数量无限制:该模式下的Socket对应的fd列表由一个数组来保存,大小不限制(默认4k)。
2.操作无限制:基于内核提供的反射模式,有活跃Socket时,内核访问该Socket的callback,不需要遍历轮询。但当所有的Socket都活跃的时候,所有的callback都被唤醒,会导致资源的竞争。既然都是要处理所有的Socket,那么遍历是最简单最有效的实现方式。

首先,select就不适合大量的并发操作,
一是它的FD数量受限,如何达到“大量”;
二是每次调用select需要将全部FD复制到内核,在FD很多时,开销很大。
然后,如果不看FD的数量,只针对活跃链接数的话,select和epoll相比,select更适合活跃链接数多的情况,因为:当活跃链接数多时,不管是select还是epoll,每次均需复制很多FD到内核;但epoll每次在内核还要开辟红黑树和双链表等数据结构,以及注册回调事件,这些操作如果太频繁,反而会降低epoll的效率。


select

  • select能监控的描述符个数由内核中的FD_SETSIZE限制,仅为1024,这也是select最大的缺点,因为现在的服务器并发量远远不止1024。即使能重新编译内核改变FD_SETSIZE的值,但这并不能提高select的性能。

  • 每次调用select都会线性扫描所有描述符的状态,在select结束后,用户也要线性扫描fd_set数组才知道哪些描述符准备就绪,等于说每次调用复杂度都是O(n)的,在并发量大的情况下,每次扫描都是相当耗时的,很有可能有未处理的连接等待超时。

  • 每次调用select都要在用户空间和内核空间里进行内存复制fd描述符等信息。

poll

  • poll使用pollfd结构来存储fd,突破了select中描述符数目的限制。

  • 与select的后两点类似,poll仍然需要将pollfd数组拷贝到内核空间,之后依次扫描fd的状态,整体复杂度依然是O(n)的,在并发量大的情况下服务器性能会快速下降。

epoll

  • epoll维护的描述符数目不受到限制,而且性能不会随着描述符数目的增加而下降。

  • 服务器的特点是经常维护着大量连接,但其中某一时刻读写的操作符数量却不多。epoll先通过epoll_ctl注册一个描述符到内核中,并一直维护着而不像poll每次操作都将所有要监控的描述符传递给内核;在描述符读写就绪时,通过回掉函数将自己加入就绪队列中,之后epoll_wait返回该就绪队列。也就是说,epoll基本不做无用的操作,时间复杂度仅与活跃的客户端数有关,而不会随着描述符数目的增加而下降。

  • epoll在传递内核与用户空间的消息时使用了内存共享,而不是内存拷贝,这也使得epoll的效率比poll和select更高。


https://www.nowcoder.com/questionTerminal/c162e1e930a34ea3ad6c8863ccff0fa2
http://www.yulibaozi.com/selectepoll.html

select、poll、epoll详解
http://www.jianshu.com/p/dfd940e7fca2

你可能感兴趣的:(操作系统)