Linux select、poll、epoll是什么意思?

流:一个流可以是文件,socket,pipe等等可以进行I/O操作的内核对象。

read:从流中读取数据;

write:往流中写入数据;

阻塞:一直等待任务,有任务到来会被唤醒;

非阻塞忙轮询:一遍又一遍地询问有没有任务;

缓冲区:先把要获取或者写入的数据缓存起来,等到合适的时机再进行io操作。为什么要使用缓冲区呢?

首先看一下图:

例如从磁盘中读取一个文件的内容,用户态从内核态取数据,需要在用户态和内核态之间切换,会比较耗性能,写入数据也是如此,因此缓冲区可以减少用户态和内核态之间切换所消耗的性能。

IO阻塞:

(1)read:如果内核态缓冲区没有数据,那么将阻塞,如果内核态缓冲区从没有数据到有数据,就会唤醒阻塞的read线程;

(2)write:如果内核态缓冲区满了,无法在写入,此时将阻塞,如果内核态缓冲区从满状态到非满状态,就会唤醒阻塞的write线程。

IO模型:

(1)阻塞IO模型:这个模型有一个明显的缺点,就是一个线程只能处理一个IO操作,如果需要处理多个IO操作,就需要创建多个线程或者进程,这显然不可取;

(2)非阻塞忙轮询IO模型:轮询所有的流,如果可读取或写入,则执行,否则处理下一个流。这个模型有两个缺点:1.在所有流都不可读取和写入的时候,会造成CPU空转,浪费系统资源;2.不能执行处理可读取或写入的流,需要遍历所有的流并进行判断是否可读取或写入,再进行处理;

(3)select模型:对于上述的非阻塞忙轮询IO模型的CPU空转的缺点进行补充。

在所有流都不可读取和写入的时候,CPU会空转,那么引入一个select代理,用于检测所有流是否可读取和可写入,如果所有流都不可读取和写入,那么这个线程将阻塞,如果至少有一个流可读取或写入,那么就会将阻塞的线程唤醒。其实select模型下,维护一个fd_set数据结构(使用的是Bitmap位图算法),每一个元素与流关联,每次调用select()方法时,需要将这个数据结构拷贝到内核态,然后内核判断哪些流可读或可写,并写入到这个数据结构然后拷贝到用户态。因此 1.如果数据结构太大,在用户态和内核态之间拷贝会很耗性能;2.在内核态中,每次都要遍历这个数据结构的所有元素,比较耗性能;3.为了减少拷贝对性能的损害,内核对这个集合的大小做了限制(1024,大小不可修改);

(4)poll模型:这个模型跟select模型类似,只是没有对fd_set数据结构集合的大小做限制,因此只解决了select模型的第三个缺点,第一、二个缺点依然存在;

(5)epoll模型:该模型基于事件驱动的方式,使用一个文件描述符来管理多个描述符,描述符的数量没有限制。每当fd就绪,就会调用系统注册的回调函数,将fd加入到readyList中。进行IO操作的时候,只需要遍历这个readyList,而不需要遍历所有的fd。因此解决了CPU空转、遍历所有fd、大集合在用户态和内核态之间拷贝的性能消耗的缺点。

 

 selectpollepoll
操作方式遍历遍历回调
底层实现数组链表红黑树
IO效率每次调用都进行线性遍历,时间复杂度为O(n)每次调用都进行线性遍历,时间复杂度为O(n)事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到readyList里面,时间复杂度O(1)
最大连接数1024(x86)或2048(x64)无上限无上限
fd拷贝每次调用select,都需要把fd集合从用户态拷贝到内核态每次调用poll,都需要把fd集合从用户态拷贝到内核态调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝

epoll是Linux目前大规模网络并发程序开发的首选模型。在绝大多数情况下性能远超select和poll。目前流行的高性能web服务器Nginx正式依赖于epoll提供的高效网络套接字轮询服务。但是,在并发连接不高的情况下,多线程+阻塞I/O方式可能性能更好。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值