五大IO模型

五大IO模型

socket在创建的时候默认是阻塞的,我们可以给socket系统调用的第2个参数传递SOCK_NONBLOCK标志,或者通过fcntl系统调用的F_SETFL命令,将其设置为非阻塞的。阻塞和非阻塞的概念能应用于所有文件描述符,而不仅仅是socket。我们称阻塞的文件描述符为阻塞I/O,称非阻塞的文件描述符为非阻塞I/O

网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作。 对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,它会经历两个阶段:

1)第一阶段:等待数据准备 (Waiting for the data to be ready)。

2)第二阶段:将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)。

对于socket流而言,

1)第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。

2)第二步:把数据从内核缓冲区复制到应用进程缓冲区。 网络应用需要处理的无非就是两大类问题,网络IO,数据计算。相对于后者,网络IO的延迟,给应用带来的性能瓶颈大于后者。网络IO模型主要有如下五种:

1)阻塞IO(blocking IO)

2)非阻塞IO(non-blocking IO)

3)多路复用IO(multiplexing IO)

4)信号驱动式IO(signal-driven IO)

5)异步IO(asynchronous IO)

其中,阻塞IO、非阻塞IO、多路复用IO和信号驱动式IO都是同步IO模型

1.阻塞IO

(1)概念

所谓阻塞IO就是当应用发起读取数据申请时,在内核数据没有准备好之前,应用会一直处于等待数据状态,直到内核把数据准备好了交给应用才结束。

(2)网络模型

在这个IO模型中,用户空间的应用程序执行一个系统调用(recvform),这会导致应用程序阻塞,什么也不干,直到数据准备好,并且将数据从内核复制到用户进程,最后进程再处理数据,在等待数据到处理数据的两个阶段,整个进程都被阻塞。不能处理别的网络IO。调用应用程序处于一种不再消费 CPU 而只是简单等待响应的状态,因此从处理的角度来看,这是非常有效的。

(3)流程描述

在调用recv()/recvfrom()函数时,发生在内核中等待数据和复制数据的过程,大致如下图:

a.用户进程调用了recv()/recvfrom()这个系统调用

b.准备数据(应用进程会被阻塞)

c.将数据从内核复制到应用空间

d.复制完成后、返回成功提示

(4)优缺点分析

优点:能够及时返回数据,无延迟

缺点:处于等待需要付出性能的代价

 

2.非阻塞IO

(1)概念

所谓非阻塞IO就是当应用发起读取数据申请时,如果内核数据没有准备好会即刻告诉应用,不会等待。

(2)网络模型

非阻塞IO是在应用调用recvfrom读取数据时,如果该缓冲区没有数据的话,就会直接返回一个EWOULDBLOCK错误,不会让应用一直等待中。在没有数据的时候会即刻返回错误标识,那也意味着如果应用要读取数据就需要不断的调用recvfrom请求,直到读取到它数据要的数据为止

(3)流程描述

在调用recv()/recvfrom()函数时,发生在内核中等待数据和复制数据的过程,大致如下图:

在调用recv()/recvfrom()函数时,发生在内核中等待数据和复制数据的过程,大致如下图:

a.应用进程向内核发起recvfrom读取数据。

b.没有数据报准备好,即刻返回EWOULDBLOCK错误码。

c.应用进程向内核发起recvfrom读取数据。

d.已有数据包准备好就进行一下 步骤,否则还是返回错误码。

e.将数据从内核拷贝到用户空间。

f.完成后,返回成功提示。

(4)优缺点分析:

优点: 能够在等待任务完成的时间里干其他活了(包括提交其他任务,也就是 “后台” 可以有多个任务在同时执行)。

缺点: 任务完成的响应延迟增大了,因为每过一段时间才去轮询一次read操作,而任务可能在两次轮询之间的任意时间完成。这会导致整体数据吞吐量的降低。

 

3.多路复用IO

(1)概念

IO复用模型的思路就是系统提供了一种函数可以同时监控多个文件描述符fd的操作,这个函数就是我们常说到的select、poll、epoll函数,有了这个函数后,应用线程通过调用select函数就可以同时监控多个fd,select函数监控的fd中只要有任何一个数据状态准备就绪了,select函数就会返回可读状态,这时询问线程再去通知处理数据的线程,对应线程此时再发起recvfrom请求去读取数据。

(2)网络模型

进程通过将一个或多个fd传递给select,阻塞在select操作上,select帮我们侦测多个fd是否准备就绪,当有fd准备就绪时,select返回数据可读状态,应用程序再调用recvfrom读取数据。

I/O复用模型会用到select、poll、epoll函数,这几个函数也会使进程阻塞,但是和阻塞I/O所不同的的,它们函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时(注意不是全部数据可读或可写),才真正调用I/O操作函数

(3)流程描述

对于多路复用,也就是轮询多个socket。多路复用既然可以处理多个IO,也就带来了新的问题,多个IO之间的顺序变得不确定了,当然也可以针对不同的编号。流程如下图所示:

a.调用select、poll和epoll函数不断轮询所负责的所有socket。

b.当有数据报准备好读取时,通知用户进程。

c.将数据从内核拷贝到用户空间。

d.完成后,返回成功提示。

(4)优缺点分析

优点:I/O多路复用技术通过把多个I/O的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降底了系统的维护工作量。多路复用IO的主要应用场景如下:

a.服务器需要同时处理多个处于监听状态或者多个连接状态的套接字。

b.服务器需要同时处理多种网络协议的套接字。

缺点:如果处理的连接数不是很多,则不一定比多线程阻塞IO性能更好,因为读取一个数据总是要发起两阶段的请求,第一次发送select请求,询问数据状态是否准备好,第二次发送recevform请求读取数据

 

4.信号驱动式IO

(1)概念

信号驱动IO不是用循环请求询问的方式去监控数据就绪状态,而是在调用sigaction时候建立一个SIGIO的信号联系,当内核数据准备好之后再通过SIGIO信号通知线程数据准备好后的可读状态,当线程收到可读状态的信号后,此时再向内核发起recvfrom读取数据的请求,因为信号驱动IO的模型下应用线程在发出信号监控后即可返回,不会阻塞,所以这样的方式下,一个应用线程也可以同时监控多个fd。

(2)网络模型

首先开启套接口信号驱动IO功能,并通过系统调用sigaction执行一个信号处理函数,此时请求即刻返回,当数据准备就绪时,就生成对应进程的SIGIO信号,通过信号回调通知应用线程调用recvfrom来读取数据。

(3)流程描述

信号驱动式IO流程如下图所示:

a.首先开启套接字的信号驱动式I/O功能,并通过sigaction系统调用来安装一个信号处理函数(进程不会被阻塞)。

b.当数据报准备好读取时,内核就为该进程产生一个SIGIO信号,此时可以在信号处理函数中调用recvfrom读取数据报,并通知数据已经准备好,正在等待处理。

c.将数据从内核拷贝到用户空间。

d.完成后,返回成功提示。

(4)优缺点分析

优点: IO复用模型里面的select虽然可以监控多个fd了,但select其实现的本质上还是通过不断的轮询fd来监控数据状态, 因为大部分轮询请求其实都是无效的,所以信号驱动IO意在通过这种建立信号关联的方式,实现了发出请求后只需要等待数据就绪的通知即可,这样就可以避免大量无效的数据状态轮询操作。

缺点:信号I/O在大量IO操作时可能会因为信号队列溢出导致没法通知;与多路IO复用类似,读取一个数据总是要发起两个阶段的请求。

 

5.异步IO

(1)概念

应用只需要向内核发送一个read 请求,告诉内核它要读取数据后即刻返回;内核收到请求后会建立一个信号联系,当数据准备就绪,内核会主动把数据从内核复制到用户空间,等所有操作都完成之后,内核会发起一个通知告诉应用

(2)网络模型

应用告知内核启动某个操作,并让内核在整个操作完成之后,通知应用,这种模型与信号驱动模型的主要区别在于,信号驱动IO只是由内核通知我们何时可以开始下一个IO操作,而异步IO模型是由内核通知我们操作什么时候完成。当进程发起异步IO操作之后,就直接返回再也不理睬了,直到kernel发送一个信号,告诉进程说IO完成。在这整个过程中,进程完全没有被阻塞。

(3)流程描述 异步IO流程如下图所示:

a.系统调用aio_read函数,启动相应的操作。

b.当有数据报准备好读取时,内核直接将数据从内核拷贝到用户空间。

c.完成后,返回成功提示。

(4)优缺点分析

优点:解决了应用程序需要先后发送询问请求、发送接收数据请求两个阶段的模式,在异步IO的模式下,只需要向内核发送一次请求就可以完成状态询问和数拷贝的所有操作

缺点:异步IO对 API 的实现者而言较为困难,还有很多系统调用不支持异步IO。

 

6.总结

在IO模型中,“同步”和“异步”区分的是内核向应用程序通知的是何种IO事件(是就绪事件还是完成事件),以及该由谁来完成IO读写(是应用程序还是内核)。显然,同步对应的是就绪事件,由应用程序完成IO读写,异步对应的是完成事件,由内核来完成IO读写。

五种网络IO模型的大致流程如下所示:

 

 

 

参考:

1.《Linux高性能服务器编程》

2. https://www.jianshu.com/p/486b0965c296

3. https://zhuanlan.zhihu.com/p/115912936

posted @ 2021-10-20 23:11  烟消00云散  阅读(188)  评论(0编辑  收藏  举报