五种IO模型
- IO有内存IO、网络IO和磁盘IO三种,通常我们说的IO时候两者, 网络IO是wocket的读取,socket在linux系统被抽象为流,IO可以理解为对流操作,对于一次IO访问,让一个read操作发生时,会经历讲个阶段
- 第一阶段:等待数据准备,数据从磁盘拷贝到内核空间
- 第二阶段:将数据从内核空间拷贝到进程空间
- 网络IO的模型大致分为一下几种:
- 阻塞IO
- 非阻塞IO
- 多路复用IO
- 信号驱动式IO
- 异步IO
-
阻塞式IO模型
对network io 来说,很多时候数据在一起开始还没到达,这个时候kemel就等足够的数据到来,这个过程整个进程都会被阻塞,当kemel一直等到数据准备好了,它会将数据从kemel中拷贝到用户内存,然后kemel返回结果,用户进程才会解除block的状态,重新运行起来
简单说就是 被系统调用但是数据没到达,数据没有到达之前,都会阻塞,知道拿到数据之后,才中新运行起来
-
非阻塞IO模型
在非阻塞IO中,用户进程需要不断的主动询问kernel数据准备好了没有,用户线程每次请求IO都会立即返回,但是为了拿到数据,需要不断询问,消耗了大量的CPU
当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。
-
IO多复用模型
IO 多路复用建立在内核提供的阻塞函数select上,用户先将需要进行IO操作的socket添加到select中,kernel会监视所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回,这个时候用户进程在进行read操作,将数据拷贝到用户进程
select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select/epoll这个函数会不断轮询所负责的所有socket,当某个socket有数据到达,就通知用户进程
为什么epoll、poll、比select更高级?
select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024
select监控socket连接时不能准确告诉用户是哪个
poll和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制, 可以理解为poll是一个过渡阶段,大家也都不用他
Epoll没有最大文件描述符数量限制
epoll最重要的优点是他可以直接告诉用户程序哪一个
-
信号驱动IO模型
应用进程告诉内核:当你数据准备好的时候,会给发送一个信号,并且调用信号处理来获取数据,这个模型是由信号模型进行驱动的
-
异步IO模型
用户进程发起read操作之后,可以去干其他的事情,从kernel的角度,当他收到了read之后,首先会将立刻返回,不会对用户进程进行任何lock,然后kerel数据准备完后,会将数据拷贝到用户的内存,发送完之后会给用户进程发送一个信号,告诉read完成
IO多路复用模型中,数据达到内核后通知用户线程,用户线程负责从内核中拷贝数据
在异步IO模型中,当用户线程收到通知时,数据已经拷贝到了用户的缓冲区,用户线程直接可以使用
相比于IO多路复用,异步IO模型并不常用,因为目前操作系统对异步IO的支持并不完善,IO多路复用也基本够用. 有很多做法是用IO多路复用模型模拟异步IO