内容目录
IO基本概述
什么是IO
- 所谓IO,无非就是输入输出,其实大家更多关注的是磁盘IO,事实上当我们在网络中传送一些数据时,本质上也是一种IO
什么是网络IO
- 拿用户请求Nginx这样的web服务器获取磁盘中的文件时,系统是如何处理的?
- 通过上面的例子,用户每一次请求都会发生一次IO操作:而每次IO,都要经由两个阶段:
- 第一步:将数据从磁盘加载至内核的内存空间(缓冲区),等待数据准备完成,时间较长
- 第二步:将数据从内核缓冲区复制到用户空间的进程内存(缓冲区),时间较短
- 第三步:Nginx封装数据为响应报文发送
- nginx下发指令给内核后,nginx是等待,还是不等待继续处理新的请求
- 数据拷贝到内核缓冲区了,通知nginx应用程序,阻塞
IO网络模型
- IO模型分为同步、异步、阻塞、非阻塞
同步/异步
- 同步/异步(关注的是消息通知机制)
- 同步:调用者发指令给被调用者,被调用者需要获取资源后再返回给调用者,那么此时调用者需要时不时去看一下,对于调用者来说很繁忙。
- 异步:调用者发指令给被调用者,被调用者需要获取资源后再返回给调用者,此时被调用者会主动将当前的运行状态通知给调用者。
阻塞/非阻塞
- 阻塞/非阻塞(关注的是调用者在等待被调用者返回结果之前所处的状态)
- 阻塞:指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起
- 非阻塞:指IO操作被调用后立即返回给用户进程一个状态值,无需等待IO操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起
IO组合模型
- 同步阻塞:将衣服扔到洗衣机,然后守在洗衣机旁边,等待什么时候洗完什么时候处理
- 同步非阻塞:将衣服扔到洗衣机,然后可以去干别的事情,是否洗完不知道,需要时不时看一下
- 异步阻塞:将衣服扔给洗衣机,还是会在旁边等着(阻塞),洗衣机洗完了会通知
- 异步非阻塞:将衣服扔给洗衣机,可以去干其他事情,等待洗衣机洗完了会通知,然后再去取衣服
五种常见IO模型
同步阻塞IO
- 当用户进程调用了
recvfrom()
这个系统调用,希望从磁盘获取数据 kernel
就开始了IO
的第一个阶段,准备数据,如果数据需要很长时间,那么就需要一直等待- 当
kernel
数据准备好了,会将数据从kenel
中拷贝到用户进程内存,然后kernel
返回数据结果,用户进程才解除阻塞状态,可以做其他事情
总结,同步阻塞IO
的特定就是在IO
执行的两个阶段都被阻塞了。那么也就意味着一个进程只能响应一个用户请求,剩下请求会被挂起,会造成每次只能响应一个请求。
同步非阻塞IO
- 当用户进程调用了
recvfrom()
这个系统调用,希望从磁盘获取数据 - 那么是否完成并不知道,需要一次一次的去问
- 当
kernel
中的数据准备好了,此时用户进程再次发起系统调用,那么它马上将数据拷贝到了用户进程内存。
所以,非阻塞IO
的特点是用户进程需要不断的主动询问kernel
数据好了没有
好处:用户进程可以处理其他任务
坏处:任务完成的响应延迟增大了,因为每过一段时间采取轮询一次操作
IO多路复用
- 当用户进程发起调用请求,不用直接与内核交互,而是找一个代理进程
select
,当用户进程调用select
,那么整个进程会阻塞在select
上(因为是由select
与内核进行交互,需要等待select
返回结果) kernel
会监视select
负责的数据,当任何一个进程的数据准备好了,select
就会返回- 当
select
用户进程返回结果后,用户程序会再次进行系统调用,将kernel
数据拷贝到用户进程
总结,select
代理进程,它这一个进程可以接收多个用户进程的请求
信号驱动IO
- 当用户进程调用了
recvfrom()
这个系统调用,希望从磁盘获取数据 - 磁盘文件中的数据如果还没有读取到内核缓冲区时,没关系,进程还可以继续运行并不阻塞
- 当磁盘数据复制到内核中后,会通知用户进程数据准备就绪
- 用户进程在发指定将内核中数据复制到用户进程中,此时进程会进入阻塞状态
异步非阻塞IO
- 当用户进程调用了
recvfrom()
这个系统调用,希望从磁盘获取数据 kernel
收到后,会立刻返回,所以不会对用户进程产生任何阻塞kernel
等待数据准备完成,并将内核数据拷贝到用户进程内存,当这一切完成之后,kernel
会给用户进程发送一个回调函数通知用户进程本次IO
完成。
IO模型对比
IO模型实现
几种网络IO模型实现
select
:对应IO/复用模型,遍历
Poll
:对应IO/复用模型
Epoll
对应IO/复用模型,具有信号驱动I/O模型某些特性
select、poll、epool区别
无论是select、poll、epool
都可以面对多个用户进程的请求,它相当于一个代理人,收集很多用户进程的请求,收集完成后,它帮你从磁盘上获取数据,复制到内核中,俺么这个数据准备没准备好,它的实现机制是不一样的。
通知方式:假设有一个用户数据准备好了,那么还有很多用户数据没准备好,那么如何通知呢?
select
和poll
是遍历扫描,效率低下epoll
采用回调机制,epoll
会主动通知,效率会更高
IO效率:假设100个用户发请求和1000个用户发请求,在遍历的时候的性能一样吗?
select
和poll
用户的请求越多,所需要遍历的就越多,需要耗时就越长epoll
采用的是回调方式,无论有多少用户,它发送的时间是一样的。
总结:
nginx
从最初设计时,就是使用epoll IO
模型,使用边缘触发机制- 同时
nginx
还支持异步IO
,用了近几年最新的服务端编程技术,来支持较好的并发。
留言