多路复用select、poll、epoll总结

多路复用select、poll、epoll总结

一、 多路复用

IO多路复用是指使用单个线程同时处理多个IO请求。在IO多路复用模型中一个线程可以监视多个文件描述符(fd),一旦某个fd就绪(读/写就绪)或者超时,就能够通知应用程序进行相应的读写操作。IO多路复用使线程不会阻塞在某一个特定的IO请求上,而是不断地去对内核通知的请求进行处理,其具体实现方式有select、poll和epoll三种
在这里插入图片描述

二、三种IO模型优缺点

2.1、Select

Select可以是非阻塞模型,非阻塞并不一定是异步模型,但异步模型一定是非阻塞的。利用 select 函数来判断某Socket上是否有数据可读,或者能否向一个套接字写入数据,防止程序在Socket处于阻塞模式中时,在一次 I/O 调用(如send或recv、accept等)过程中,被迫进入“锁定”状态;
在这里插入图片描述

优点:
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。
缺点:
select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024(32位1024,64位2048),可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。
第二个缺点,对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低。
第三个缺点,select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理,因此需要维护一个用来存放大量fd的数据结构(fd_set)。fd_set简单地理解为一个长度是1024的比特位,每个比特位表示一个需要处理的FD,如果是1,那么表示这个FD有需要处理的I/O事件,否则没有,其是连续存储的。每次select查询都要遍历整个事件列表。这样会使得用户空间和内核空间在传递该结构时复制开销大。

2.2、poll

poll的机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制。poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
优点:
在使用该结构的时候,不用进行比特位的操作,而是对事件本身进行操作就行。同时还可以自定义事件的类型。这样的好处是在内存中存放就不需要连续的内存地址,很像是list队列结构,读或者写事件数量(文件描述符数量)理论上是无限的,取决于内存的大小。它没有最大连接数的限制,原因是它是基于链表来存储的。
缺点:
内核需要将消息传递到用户空间,都需要内核拷贝动作。需要维护一个用来存放大量fd的数据结构,使得用户空间和内核空间在传递该结构时复制开销大。大量的fd被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。

2.3、epoll

在这里插入图片描述

epoll给出了一个新的模式,直接申请一个epollfd的文件,对这些进行统一的管理,初步具有了面向对象的思维模式。可理解为event poll,epoll会把哪个流发生哪种I/O事件通知我们。所以epoll是事件驱动(每个事件关联fd)的,此时我们对这些流的操作都是有意义的。复杂度也降低到了O(1)。
epoll通过在Linux内核中申请一个简易的文件系统。把原先的select/poll调用分成了3个部分:
调用epoll_create()建立一个epoll对象(在epoll文件系统中为这个句柄对象分配资源);
调用epoll_ctl向epoll对象中添加这些连接的套接字;
调用epoll_wait收集发生的事件的连接.
如此一来只需要在进程启动时建立一个epoll对象,然后在需要的时候向这个epoll对象中添加或者删除连接。同时,epoll_wait的效率也非常高,因为调用epoll_wait时,并没有一股脑的向操作系统复制这些连接的句柄数据,内核也不需要去遍历全部的连接。

三、select、poll、epoll 区别总结:

3.1、支持一个进程所能打开的最大连接数

select:单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。
poll:poll本质上和select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的。
epoll:虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接。

3.2、fd剧增后带来的IO效率问题

select:因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。
poll:同上
epoll:因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。

3.3、消息传递方

select:内核需要将消息传递到用户空间,都需要内核拷贝动作
poll:同上
epoll:epoll通过内核和用户空间共享一块内存来实现的。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值