IO模型

select模型

在Linux内核中设计了一个叫做select的函数,这个函数在内核态中对fd集合进行遍历,如果对应的fd接收到客户端的抵达数据,则会返回给用户态调用方(注意用户态发送select调用的时候依然会处于堵塞状态)。

一次select函数调用,会发生一次系统内核调用,和内核态内部的n多次就绪文件符的read函数调用。

poll模型

poll也是和select相似,通过一次系统调用,然后在内核态中对连接的文件描述符集合进行遍历判断是否有就绪状态的连接接收到了网卡数据。但是select函数中只能监听1024个文件描述符(之所以是1024,我推断是为了尽量避免过多的集合在用户态和内核态之间的拷贝情况发生),而poll函数则是去除掉了这块的限制。

epoll模型

通过上边对select介绍,可以发现它虽然将之前在用户态循环调用内核态的设计改进为了在用户态发起调用触发内核态中的循环遍历,但是依然存在以下几个不足点。

  • select函数在从用户态拷贝fd集合传入内核态之后,后续主要关注的点就是哪个fd的就绪状态发生了改变。举个应用场景解释下:内核态中已经存在一个fd集合,这个集合中的任一fd的状态发生变更,则整个fd集合都需要返回给到用户态,这个拷贝过程会将状态没有变化的fd也返回。

  • select函数在内核态中依然是通过遍历的方式来判断究竟哪个fd已经处于就绪状态。

因此,epoll模型就是基于这些不足点的基础上去进行优化的。

  • 用户态无需将整份fd数据在用户态和内核态之间进行拷贝,只会拷贝发生变化的fd数据。

  • 内核态中不再是通过循环遍历的方式来判断哪些fd处于就绪状态,而是通过异步事件通知的方式告知。

  • 内核态会将有数据抵达的fd返回到用户态,此时用户态可以减少不必要的遍历操作。

epollo_wait在解决大量fd拷贝的问题上引入了mmap的技术进行优化。mmap将用户空间的一块地址和内核空间的一块地址同时映射到相同的一块物理内存地址(不管是用户空间还是内核空间都是虚拟地址,最终要通过地址映射映射到物理地址),使得这块物理内存对内核和对用户均可见,减少用户态和内核态之间的数据交换。

posted @ 2023-01-20 21:05  Dazzling!  阅读(19)  评论(0编辑  收藏  举报