Unix的五种IO模型介绍

前言

以前打算总结一下Java的BIO(IO),AIO,NIO,最后一步步深刻,发现Unix(Linux)的IO模型须要提早掌握,因此先总结一下Unix的IO模型。linux

概述

Java IO 与 Unix IO 的关系(非严格对应)

Unix网络编程中介绍了五种IO模型,分别是:阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO。
Java的IO模型与Unix的IO模型的对应关系以下所示(这个对应关系并不严格):编程

Java-IO模型 Unix-IO模型
BIO 阻塞式IO
NIO IO多路复用
AIO 异步IO

数据的内核态和用户态

linux-kernal-user.png
在进行IO模型讲解以前,先讲讲数据的两个状态:内核态和用户态。
咱们将文件从磁盘加载到内存中。操做系统是怎么作的?
第一步:由于咱们的全部程序,都是和操做系统的内核进行交互,因此文件首先是从磁盘加载到内核,这时候文件是处于内核态。
第二步:文件从内核再加载到内存中,应用程序此时才能够在内存中进行读写操做。这个时候的文件就是内核态。
因此Unix的五种IO模型的不一样指出,就是这两个步骤的处理流程不一样。网络

Unix五种IO模型分别介绍

阻塞式IO

1-BIO.jpg
这种模式很简单,系统给调用recvfrom函数以后,线程一直处于等待状态,一直等到:
第一步文件加载到内核态完成,第二步文件加载到用户态完成。异步

非阻塞IO

2-NIO.jpg
系统不停的经过recvfrom进行轮询,一直到第一步完成,而后在第二步阻塞式的将数据从内核态加载到用户态。
这里的非阻塞IO模式,主要是指第一步,加载数据到内核态,这个过程是非阻塞的,经过轮询来判断数据是否在内核准备好。socket

IO多路复用

3-MIO.jpg
系统首先经过select,阻塞式的查看内核数据是否准备完毕。
当内核数据加载完成以后,系统会调用recvfrom,将内核态的数据加载到用户态。
这里看起来第一步和第二步都是阻塞式操做,可是,select能够在极小代价的状况下,同时处理多个文件句柄(包括socket)。函数

信号驱动IO

4-SIO.jpg
第一步,至关于系统注册一个回调函数,当内核数据准备好了以后通知我。
此时系统能够作其余的事情,并不须要阻塞式的等待内核数据。
第二步,阻塞式调用recvfrom,将内核的数据加载到用户态。spa

异步IO

5-AIO.jpg
这个模型在理论上来讲,是真正的异步模型,由于在以上四种模型中,在第二步:数据从内核态加载到用户态,都是同步操做。
而在该模型中,系统在加载文件的时候,只须要经过aio_read注册一个回调,当文件完成了内核态,用户态的加载以后,通知当前系统。
在这个过程当中,系统不用等待,能够执行其余的运算任务。操作系统

汇总对比

6-IO.jpg
这张图是对以上五种IO模型的汇总比较,总的来讲,越靠后的模型在理论上来讲就越高效。
前面的四种IO模型【阻塞IO、非阻塞IO、IO多路复用、信号驱动IO】,都属于同步IO,只有最后一种模型是真正的异步【异步IO】.net

系统调用介绍

1.Java的NIO老版本使用的是select模式,但后来改为了epoll,为何?

由于select是轮询的模式,不停的检查文件句柄的状态。
epoll是callback的模式,当文件句柄准备好了以后,直接进行回调,更高效。线程

2.Java有真正的AIO模式吗?

在Windows系统下,经过IOCP实现。
在Linux系统下,没有,由于Linux系统下的AIO底层还是epoll。
(我的猜想,这也是为何Netty使用了NIO,而没有使用AIO)

他山之石

以对话的形式讲述,比较易于理解
漫话:如何给女友解释什么是Linux的五种IO模型?

数据的内核态,用户态,这篇文章也有讲到,同时介绍了高效的数据传输方式:
zero-copy

相关文章
相关标签/搜索