漫谈5种IO模型

1. 什么是IO

IO (Input/Output,输入\输出)即数据的读取(接收)或写入(发送)操作,通常用户进程中的一个完整IO分为两阶段:用户进程空间<–>内核空间、内核空间<–>设备空间(磁盘、网络等)。IO有内存IO、网络IO和磁盘IO三种,通常我们说的IO指的是后两者

漫谈5种IO模型

LINUX中进程无法直接操作I/O设备,其必须通过系统调用请求kernel来协助完成I/O动作;内核会为每个I/O设备维护一个缓冲区。

对于一个输入操作来说,进程IO系统调用后,内核会先看缓冲区中有没有相应的缓存数据,没有的话再到设备中读取,因为设备IO一般速度较慢,需要等待;内核缓冲区有数据则直接复制到进程空间

所以,对于一个网络输入操作通常包括两个不同阶段:
(1 )等待网络数据到达网卡→读取到内核缓冲区,数据准备好;
(2 )从内核缓冲区复制数据到进程空间

《UNIX网络编程》说得很清楚,5种IO模型分别是阻塞IO模型、非阻塞IO模型、IO复用模型、信号驱动的IO模型、异步IO模型

1. 阻塞IO模型

漫谈5种IO模型
进程发起IO系统调用后,进程被阻塞,转到内核空间处理,整个IO处理完毕后返回进程。操作成功则进程获取到数据
例如:
小明去火车站买票,排队三天买到一张退票。
耗费:在车站吃拉撒睡3天,其他事一件没干

2. 非阻塞IO模型

漫谈5种IO模型

进程发起IO系统调用后,如果内核缓冲区没有数据,需要到IO设备中读取,进程返回一个错误而不会被阻塞;进程发起IO系统调用后,如果内核缓冲区有数据,内核就会把数据返回给进程。

对于上面的非阻塞IO模型来说,内核数据没准备好需要进程阻塞的时候,就返回一个错误,以使得进程不被阻塞
例如:
小明去火车站买票,隔12小时去火车站问有没有退票,三天后买到一张票。
耗费:往返车站6次,路上6小时,其他时间做了好多事

3. IO复用模型

漫谈5种IO模型
多个的进程的IO可以注册到一个复用器( select)上,然后用一个进程调用该select,select会监听所有注册进来的IO;

如果select监听的IO在内核缓冲区都没有可读数据,select调用进程会被阻塞;而当任一 IO在内核缓冲区中有可用数据时,select调用就会返回;
而后select调用进程可以自己或通知另外的进程(注册进程)来再次发起读取IO,读取内核中准备好的数据

典型应用: select、 poll、 epoll三种方案,nginx都可以选择使用这三个方案

events {
worker_ connections 1024;
use epoll;
}

select、poll、 epoll在Linux中IO复用 的实现方式主要有
select, poll和epoll
Select:注册IO、阻塞扫描,监听的IO最大连接数不能多于FD_ SIZE;
Poll:原理和Select相似,没有数量限制,但IO数量大扫描线性性能下降;
Epoll :事件驱动不阻塞, mmap实现内核与用户空间的消息传递,数量很大,Linux2.6后内核支持
例如:

l.select/poll
小明去火车站买票,委托黄牛,黄牛三天内买到票,然后打便所有人要买票人的电话找到小明,小明去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,等待通知3小时

2.epoll
小明去火车站买票,委托黄牛,黄牛买到后即通知小明去领,然后小明去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,无需打电话

4. 信号驱动IO模型

漫谈5种IO模型
当进程发起一个IO操作,会向内核注册一个信号处理函数,然后进程返回不阻塞;当内核数据就绪时会发送一个信号给进程,进程便在信号处理函数中调用IO读取数据
例如:
小明去火车站买票,给售票员留下电话,有票后,售票员电话通知小明,然后小明去火车站交钱领票。
耗费:往返车站2次,路上2小时,免黄牛费100元,无需打电话

5. 异步IO模型

漫谈5种IO模型
当进程发起一个IO操作,进程返回(不阻塞),但也不能返回结果;内核把整个IO处理完后,会通知进程结果。如果IO操作成功则进程直接获取到数据
例如:
小明去火车站买票,给售票员留下电话,有票后,售票员电话遇知小明并快递送票上门。
耗费:往返车站1次,路上1小时,免黄牛费100元,无需打电话

nginx相比于apache有更高的并发,可以接收处理更多的访问请求,这得益于IO模型

同步I/O引起进程阻塞,直到I/O操作完成
异步I/O不会引起进程阻塞

阻塞式I/O, 非阻塞I/O, I/O复用由于都导致了请求进程阻塞,所以均属于同步I/O。

漫谈5种IO模型
nginx高并发使用的是epoll的方式,提供给用户访问,复制数据的一些操作交由内核完成。自身做的事情越少接待的用户请求就越多。