计算及网络:IO模型

【关于作者】

关于我的恶化,我目前蚂蚁金服搬砖任职,在营销投放领域工作了多年,目前在专注于内存数据库相关的应用学习,如果你有任何技术交流或大厂内推及面试咨询,都可以从我的个人博客(https://0522-isniceday.top/)联系上我~

1.为什么IO会阻塞

1.1.TCP中的发送缓冲区和接收缓冲区

TCP的发送缓冲区:TCP的接收队列的数据没有应用程序读取或者读取的速度比较慢,发送缓冲区已发送未确认的数据越来越多,最终导致输出操作阻塞

TCP的接收缓冲区:同样的,接收端接收数据后放入到接收缓冲区中,然后对接收的数据返回一个ack确认信息,如果接收端还没有发送ack信息出去,或者应用进程一直没来取接受缓冲区已接受已确认的数据,那么就不会清除接收缓冲区的数据。

1.2.UDP的阻塞情况

UDP的输入操作:如果UDP套接字没有一个完整的数据报可读,那么就会导致输入操作阻塞;

UDP的输出操作:UDP没有真正的发送缓冲区,内核只是复制应用进程数据并把它沿着协议向下传送,所以对于一个设置为阻塞的UDP套接字,输出函数不会因为与TCP同样的原因导致阻塞,但是可能因为其他原因而阻塞。

1.3.ACCEPT阻塞

如果针对一个阻塞的套接字调用accept函数,并且连接请求还未到达,那么进程会进入睡眠状态,阻塞代表的是当前进程需要等待该函数执行完毕才可以进行下一步的处理(因此Redis的IO模型中listen返回的监听套接字都是非阻塞模式)。对于一个非阻塞的套接字,这种情况,会立刻返回一个EWOULDBLOCK错误。

1.4.Connect阻塞

如果对一个阻塞的套接字调用connect函数,一直要等到收到发出的SYN的ACK为止才返回,所以每个connect至少会阻塞进程至少一个到服务器的RTT时间。对于非阻塞的套接字,这种情况会返回一个EINPROGRESS错误。

为了避免阻塞导致IO性能下降,所以衍生出了几种IO模型,下面我们来介绍下。

2.五种IO模型

下述的IO模型可以看做从已连接套接字中读取TCP数据这一IO过程,因为socketfd的数据都存储在内核中

一般而言,一个输入操作一般会经历如下过程:

  1. 等待数据准备好
  2. 从内核复制到进程:这里的数据复制,一般是应用进程调用了某个IO方法之后,陷入系统调用,在内核态完成的

image-20201028084848560

下面我们通过UDP的recvfrom()函数来说明具体的IO模型。

2.1.阻塞I/O模型

阻塞主进程:会等待数据准备好,例如使用了阻塞的已连接套接字,因为会导致send()阻塞读取tcp的数据

image-20201029085102627

如上图,在应用进程调用 recvfrom()之后,陷入内核态,直到数据报到达并且复制到应用进程缓冲区之后才返回到用户态。

或者在系统调用期间发生错误,也会立刻返回。

这种I/O称为阻塞I/O。

2.2.非阻塞I/O模型

image-20201029085245393

轮询:当我们将套接字设置为非阻塞模式的时候,内核会这样处理IO操作,原本IO操作需要阻塞主进程,当非阻塞时,是直接报错,还不是阻塞主进程。上面的例子中,调用recvfrom()之后,因为数据没有准备好,所以内核直接返回一个EWOULDBLOCK错误,直到数据准备好了,才复制数据到进程空间,并返回系统调用继续处理进程逻辑。

而应用进程会不断轮询调用recvfrom()函数,这种处理方式我们称为polling(轮训),持续到轮训内核,查看数据是否准备好。这种方式的缺点是会消耗大量的CPU时间

2.3.IO复用模型

IO复用:通过一个支持同时感知多个描述符的函数系统调用,阻塞在这个系统调用。等待某一个或某几个描述符准备就绪,再去读写。例如select,poll,epoll系统调用可以实现此类功能功能。这种模型不用阻塞在真正的I/O系统调用上。

image-20201029085514237

与非阻塞IO相比,其实就是将轮询每一个fd抽象为了select函数调用来实现

在多线中使用阻塞I/O,即每个文件描述符一个线程,与I/O复用模型很类似,每个线程可以自由调用阻塞式I/O系统调用。

2.4.信号驱动式IO模型

所谓信号驱动式I/O(signal-driven I/O),就是指在描述符准备就绪的时候,让内核发送一个SIGIO信号通知应用进程进行后续的数据读取等处理。工作原理如下图所示:

image-20201101160607451

注册了SIGIO信号处理函数,开启了信号驱动式IO之后,就可以继续执行程序了,等到数据报准备好之后,内核会发送一个SIGIO信号给应用进程,然后应用进程在信号处理函数中调用recvfrom读取数据报。

这种模型在内核等待数据报达到期间进程不会被阻塞,可以继续执行

2.5.异步IO模型

可以发现,上面所有的I/O模型都会在某一个执行点阻塞,并不是真正的异步的。其实就是通知的时间不同

image-20201031102929395

通过异步处理函数如aio_read告知内核启动某个动作,并且让内核在整个操作完成之后再通知应用进程,内核会在把数据复制到用户空间缓冲区之后再进行通知。整个IO过程应用进程都不会被阻塞

3.IO复用模型

3.1.select

3.2.poll

3.3.epoll

转载链接:https://www.itzhai.com/articles/necessary-knowledge-of-network-programming-graphic-socket-core-insider-and-five-io-models.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

哈哈哈张大侠

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

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

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

打赏作者

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

抵扣说明:

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

余额充值