I/O多路复用(一)

目录

一、阻塞 I/O、非阻塞的 I/O、异步 I/O

1. 阻塞 I/O

2. 非阻塞的 I/O

3.  异步 I/O

二、I/O多路复用

1.select

2.poll

3.epoll

三、Reactor 模式。    

四、Proactor模式

五、【参考资料】


一、阻塞 I/O、非阻塞的 I/O、异步 I/O

        阻塞是在服务器和客户端传输过程中,read阶段的等待,等待的是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程。

1. 阻塞 I/O

        当用户程序执行 read ,线程会被阻塞,一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read 才会返回。(注意:read读取是同步过程)。

2. 非阻塞的 I/O

        非阻塞的 I/O表示:read 请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据准备好,内核将数据拷贝到应用程序缓冲区,read调用才可以获取到结果。(注意:read读取是同步过程)。

3.  异步 I/O

        异步 I/O是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待。 当我们发起 aio_read (异步 I/O)之后,就立即返回,内核自动将数据从内核空间拷贝到用户空间,这个拷贝过程同样是异步的,内核自动完成的,和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作。

二、I/O多路复用

        I/O多路复用支持只使用一个进程来维护多个 Socket。I/O 多路复用技术会用一个系统调用函数来监听我们所有关心的连接,也就说可以在一个监控线程里面监控很多的连接。只有当连接上有数据的时候,线程才去发起读请求。

        select/poll/epoll 就是内核提供给用户态的多路复用系统调用,线程可以通过一个系统调用函数从内核中获取多个事件。

1.select

        select实现多路复用的方式是,将已连接的 Socket 都放到一个文件描述符集合,然后调用 select 函数将文件描述符集合拷贝到内核里,让内核来检查是否有网络事件产生,检查的方式很粗暴,就是通过遍历文件描述符集合的方式,当检查到有事件产生后,将此 Socket 标记为可读或可写, 接着再把整个文件描述符集合拷贝回用户态里,然后用户态还需要再通过遍历的方法找到可读或可写的 Socket,然后再对其处理。

        所以,对于 select 这种方式,需要进行 2 次「遍历」文件描述符集合,一次是在内核态里,一个次是在用户态里 ,而且还会发生 2 次「拷贝」文件描述符集合,先从用户空间传入内核空间,由内核修改后,再传出到用户空间中。

        select 使用固定长度的 BitsMap,表示文件描述符集合,而且所支持的文件描述符的个数是有限制的,在 Linux 系统中,由内核中的 FD_SETSIZE 限制, 默认最大值为 1024,只能监听 0~1023 的文件描述符。

2.poll

        poll 不再用 BitsMap 来存储所关注的文件描述符,取而代之用动态数组,以链表形式来组织,突破了 select 的文件描述符个数限制,当然还会受到系统文件描述符限制。

        select和poll都是使用「线性结构」存储进程关注的 Socket 集合,因此都需要遍历文件描述符集合来找到可读或可写的Socket,时间复杂度为O(n),而且也需要在用户态与内核态之间拷贝文件描述符集合,这种方式随着并发数上来,性能的损耗会呈指数级增长。

3.epoll

        epoll 用以下两种方式提高了性能和效率:在内核里使用红黑树来跟踪进程所有待检测的文件描述字;epoll 在内核里使用红黑树来跟踪进程所有待检测的文件描述字。

        epoll 支持两种事件触发模式,分别是边缘触发(edge-triggered,ET)和水平触发(level-triggered,LT)。

  • 边缘触发:有数据时服务器端只通知一次,一般和非阻塞 I/O 搭配使用。
  • 水平触发:只要有数据 ,就一直通知 。

        select/poll 只有水平触发模式,epoll 默认的触发模式是水平触发,但是可以根据应用场景设置为边缘触发模式。

三、Reactor 模式。    

        Reactor 是非阻塞同步网络(非阻塞I/O)模式。Reactor 指的是「对事件反应」,也就是来了一个事件,Reactor 就有相对应的反应/响应。

        事实上,Reactor 模式也叫 Dispatcher 模式,我觉得这个名字更贴合该模式的含义,即 I/O 多路复用监听事件,收到事件后,根据事件类型分配(Dispatch)给某个进程 / 线程。

        Reactor 模式主要由 Reactor 和处理资源池这两个核心部分组成,它俩负责的事情如下:

  • Reactor 负责监听和分发事件,事件类型包含连接事件、读写事件;
  • 处理资源池负责处理事件,如 read -> 业务逻辑 -> send;

四、Proactor模式

        Proactor 采用了异步 I/O 技术,所以被称为异步网络模型。Proactor 感知的是已完成的读写事件,而不需要像 Reactor 感知到事件后,还需要调用 read 来从内核中获取数据。

五、【参考资料】

这次答应我,一举拿下 I/O 多路复用!

如何深刻理解Reactor和Proactor? - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烫青菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值