HI!我是小小,我们又见面了,今天是国庆假期的最后一天,在这最后一天,举国同庆的时刻。。。。我们一块来学习IO,这一次,学习 NIO,BIO,AIO等各种IO

Linux 基础知识回顾

用户空间和内核空间

现在的操作系统都采用虚拟寻址,处理器先产生一个虚拟地址,然后通过地址翻译成为物理地址,再通过总线的传递,最后处理器拿到某个物理地址返回的字节。
对于32位操作系统来说,它的寻址空间,为4G,操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限,为了保证用户进程不能直接操作内核,保证内核安全,操作系统把虚拟空间划分为两个部分,一部分为内核空间,一部分为用户空间。
对于Linux系统来说,把高直接,1G,给内核使用,称之为内核空间。把低的3G字节,送给进程使用,称之为用户空间。

直接IO和缓存IO

文件系统IO分为直接IO和缓存IO。

缓存IO

读操作

操作系统会检查内核的缓冲区有没有需要的数据,如果已经有缓存了,那么就直接从缓存中返回,否则会从磁盘中读取,然后缓存在操作系统的缓存中。

写操作

把数据从用户空间复制到内核空间的缓存中,并提示用户写操作完成,什么时候写入磁盘,由操作系统随机决定。除非强制调用sync命令。
举个栗子,对于write命令来说,数据会先被拷贝进入缓冲区,在拷贝到缓冲区以后才会写入到设备中。
详解 | 求你别用效率低下的I/O了,要不试试这种I/O插图

直接IO

详解 | 求你别用效率低下的I/O了,要不试试这种I/O插图(1)
直接IO相对于缓存IO少了拷贝到应用进程缓冲区这一步

阻塞和同步

这一小节介绍什么是阻塞,什么是同步

阻塞和非阻塞

阻塞:往往需要等待缓冲区中的数据准备好过后才处理其他事情,否则一直等待在哪。
非阻塞: 当我们的进程访问我们的数据缓冲区的时候,如果数据没有准备好则直接返回,当数据读取完毕以后,会直接触发,提前监听好的事件的回调函数。若准备好,也会直接返回。

同步异步

同步: 应用程序要直接参与IO的读写操作。
异步: 所有的IO读写交给系统处理,应用程序秩序要等待通知即可,当读的时候,会调用之前设定好的应用程序的回调函数,当写的时候,会调用之前设定好的应用程序的回调函数。

常见的IO模型

常见的IO模型有,阻塞IO,非阻塞IO,I/O复用,信号驱动I/O,异步I/O
比较如下图
详解 | 求你别用效率低下的I/O了,要不试试这种I/O插图(2)
以读取数据为例子
BIO: 如果数据源没有数据会进入阻塞状态,直到获取到数据
NIO,如果数据源没有数据,会直接返回0,不阻塞。
AIO: 全称异步+非阻塞
详细的见下一节

BIO,NIO,AIO

BIO

详解 | 求你别用效率低下的I/O了,要不试试这种I/O插图(3)
同步阻塞IO,服务器实现模式为一个连接一个线程,客户端有连接请求时服务器就需要启动一个线程进行处理,后期可以通过线程池的方式提高性能。适用于连接数目比较小,固定的架构。

NIO

客户端发送的链接请求都会注册到多路复用器上,多路复用器会轮询到连接有IO请求时才启动一个线程进行处理。NIO方式适用于连接数目多,且连接比较短的架构,例如聊天服务器。

IO多路复用模型

IO多路复用,IO就是指我们网络IO,多路指多个TCP连接,复用指复用一个或少量线程,串起来理解就是多个网络IO复用一个或少量的线程处理这些连接。
详解 | 求你别用效率低下的I/O了,要不试试这种I/O插图(4)

核心: 能处理更多的链接

常用的复用模型,select poll,epoll

select

详解 | 求你别用效率低下的I/O了,要不试试这种I/O插图(5)
select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述符就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。

poll

poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。

epoll

epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就绪态,并且只会通知一次。还有一个特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。

比较

详解 | 求你别用效率低下的I/O了,要不试试这种I/O插图(6)

应用和框架

Jetty、Mina、Netty、Dubbo、ZooKeeper 之间的通信,都是基于NIO方式实现。
常用的框架有Netty

AIO

详解 | 求你别用效率低下的I/O了,要不试试这种I/O插图(7)
详解 | 求你别用效率低下的I/O了,要不试试这种I/O插图(8)
一个有效请求一个线程,客户端IO请求都是由OS完成监听和执行的,常用的应用场景有相册服务器。

关于作者

我是小小,一个生于二线,活在一线的程序猿,该程序猿相当相当的佛系,我是小小,我们下期再见。