IO模型

来自智得网
跳转至: 导航、​ 搜索

简介

IO示意图

IO是计算机术语,是Input(输入)和Output(输出)的简称。

IO分为磁盘IO和网络IO,磁盘IO是指应用程序对磁盘数据进行读写的操作,网络IO是指应用程序对网络数据进行读写的操作。

IO操作一般和读操作,写操作关联。读操作是应用程序将数据从IO设备(磁盘或者网络)读取出来可以用于业务操作,写操作一般是应用程序将程序处理的结果写到IO设备(磁盘或者网络)。

一般的操作系统,例如Linux下,应用程序不能直接和IO设备交互,所以读写操作要经过系统调用调用内核的IO能力,内核再与IO设备进行交互。

因为IO设备一般读写速度都较低,为了提高读写的效率,一般都会采用读写缓冲区的方式,将数据提前缓冲做批量的读写操作。对于磁盘来说,Linux内核提供了统一的缓冲区能力,在进行读的时候会先从系统缓冲区中读取数据,当数据在缓冲区不存在的时候在进行实际的读取,读取之后会先放在系统缓冲区。

写入磁盘的时候,一般也会先写入磁盘缓冲区,之后批量进行磁盘的写入,写缓冲不仅仅可以提高写入的效率,还减少了磁盘的寻道时间。但是在断电情况下,可能会丢失部分数据。

同理,在网络IO的时候,内核也提供了Socket缓冲区作为数据的读写缓冲,但是因为网络IO不是设备级别,而是链接级别的,所以每个socket都会有自己的读缓冲区和写缓冲区。

综上,读操作需要2次数据拷贝,分别是将数据从用户空间拷贝到内核空间,从内核空间拷贝到IO设备。同理写操作也需要2次数据拷贝,将数据从IO设备拷贝到内核空间,再从内核空间拷贝到用户空间。

IO模型是指在进行IO操作的时候的线程模型以及读写模式,一般可以分为几种,BIO,NIO以及AIO。

原理

BIO模型

BIO

BIO是指阻塞IO,阻塞IO在读写的时候会进行等待,直到成功获取或者写入数据。一般情况下写操作已经准备好数据,只要把数据写入内核缓冲区就可以结束,但是读操作需要等待IO设备返回数据,一般有较长的等待时间,所以本文都以读操作场景来分析各种IO模型。

BIO实现的逻辑简单,但是缺点也很明显,因为需要阻塞等待数据返回,所以BIO在等待的过程中需要一个线程,即BIO是一个链接一个线程的模式,线程资源是宝贵的系统资源,一个线程占用一定的内存资源,所以线程不是可以无限创建的,而且线程较多的情况下,系统的线程切换也会更加频繁,也会影响到系统的响应能力以及响应时间。所以BIO在支持高并发方面存在较大的瓶颈。

BIO在阻塞期间,是不需要CPU的,会发生线程的上下文切换,使进行IO操作的业务线程处于阻塞状态。当数据返回的时候,再将该业务线程回复可运行状态。在阻塞状态下,线程是不会获得CPU执行机会的,也不会浪费CPU时间片,所以在有大量IO请求的系统,一般CPU使用率或者系统负载不高。
NIO模型

NIO

NIO是非阻塞IO,是和阻塞IO对应的,非阻塞IO在读取不到数据的时候,不会进行阻塞等待,而是会直接返回。

所以阻塞IO需要业务线程不停的轮训请求数据,直到数据被准备好。

因为不需要阻塞等待数据,所以请求数据的线程在请求结束之后就可以释放,所以NIO模式下不需要一个网络请求长期占用一个线程资源,可以有效的节约线程数量,但是NIO引入了新的问题,就是轮训操作是较为消费系统资源的,所以多个网络链接高频轮训效率较低,而且轮训机制的实效性较差。

多路复用

多路复用是为了解决NIO中轮训带来的性能损耗而诞生。

多路复用中的多路指的是多条网络链接,即多个链接。

复用的是IO线程,多路复用只会有一个线程进行轮训,减少CPU消耗。当线程获取到数据之后,会再通知业务的回调线程进行数据的读写操作,在编程模型中称为Reactor模型。

多路复用模型

多路复用中,应用程序有三类线程:

业务线程进行数据读写的业务线程,该类线程调用读写操作之后立即返回。

多路复用线程,该线程轮训所有的网络IO,一旦有网络IO准备好数据,多路复用线程会调用数据处理线程进行数据处理。

数据处理线程,该类线程真正读取数据,之后再进行业务处理,数据处理线程有两种模式,一种模式是IO处理和业务处理使用同一个线程,另一种模式是IO线程和处理线程分开。

在Linux系统中,多路复用有三种API,分别是select,poll和epoll。

其中select和poll都是通过轮训的方式遍历所有的文件句柄,判断这些句柄是否有准备好数据,select、poll不同的点在于poll可以轮训的IO句柄没有限制,但是select只能轮训1024个句柄。

而且select底层使用的数据结构是数组,而poll使用的是链表。

相比于select和poll,epoll有了较大的改进,epoll不再使用轮训的方式判断IO是否准备好,而是通过事件回调的机制,在内核准备好数据之后,会通过epoll,epoll再去通知业务线程。

API 获取数据方式 文件句柄限制 时间复杂度 底层数据结构
select 拷贝数据 1024 Θ(N) 数组
poll 拷贝数据 无限制 Θ(N) 链表
epoll IO句柄复制数据,epoll不拷贝 无限制 Θ(1) 红黑树

AIO

在多路复用中,epoll已经实现了事件通知机制,但是IO分为两个阶段,第一个阶段是数据准备,第二个阶段是数据拷贝,epoll只可以通知数据准备完成,应用程序在获取数据的时候依然需要等待数据拷贝。

AIO的数据准备和数据拷贝都由内核完成,然后通知应用程序来获取数据。