unix和Linux的五种io模型,Unix的五种IO模型介绍

前言

之前打算总结一下Java的BIO(IO),AIO,NIO,最后一步步深入,发现Unix(Linux)的IO模型需要提前掌握,所以先总结一下Unix的IO模型。

概述

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

数据的内核态和用户态

unix和Linux的五种io模型,Unix的五种IO模型介绍_第1张图片

在进行IO模型讲解之前,先讲讲数据的两个状态:内核态和用户态。

我们将文件从磁盘加载到内存中。操作系统是怎么做的?

第一步:因为我们的所有程序,都是和操作系统的内核进行交互,所以文件首先是从磁盘加载到内核,这时候文件是处于内核态。

第二步:文件从内核再加载到内存中,应用程序此时才可以在内存中进行读写操作。这个时候的文件就是内核态。

所以Unix的五种IO模型的不同指出,就是这两个步骤的处理流程不同。

Unix五种IO模型分别介绍

阻塞式IO

unix和Linux的五种io模型,Unix的五种IO模型介绍_第2张图片

这种模式很简单,系统给调用recvfrom函数之后,线程一直处于等待状态,一直等到:

第一步文件加载到内核态完成,第二步文件加载到用户态完成。

非阻塞IO

unix和Linux的五种io模型,Unix的五种IO模型介绍_第3张图片

系统不停的通过recvfrom进行轮询,一直到第一步完成,然后在第二步阻塞式的将数据从内核态加载到用户态。

这里的非阻塞IO模式,主要是指第一步,加载数据到内核态,这个过程是非阻塞的,通过轮询来判断数据是否在内核准备好。

IO多路复用

unix和Linux的五种io模型,Unix的五种IO模型介绍_第4张图片

系统首先通过select,阻塞式的查看内核数据是否准备完毕。

当内核数据加载完成之后,系统会调用recvfrom,将内核态的数据加载到用户态。

这里看起来第一步和第二步都是阻塞式操作,但是,select可以在极小代价的情况下,同时处理多个文件句柄(包括socket)。

信号驱动IO

unix和Linux的五种io模型,Unix的五种IO模型介绍_第5张图片

第一步,相当于系统注册一个回调函数,当内核数据准备好了之后通知我。

此时系统可以做其他的事情,并不需要阻塞式的等待内核数据。

第二步,阻塞式调用recvfrom,将内核的数据加载到用户态。

异步IO

unix和Linux的五种io模型,Unix的五种IO模型介绍_第6张图片

这个模型在理论上来说,是真正的异步模型,因为在以上四种模型中,在第二步:数据从内核态加载到用户态,都是同步操作。

而在该模型中,系统在加载文件的时候,只需要通过aio_read注册一个回调,当文件完成了内核态,用户态的加载之后,通知当前系统。

在这个过程中,系统不用等待,可以执行其他的运算任务。

汇总对比

unix和Linux的五种io模型,Unix的五种IO模型介绍_第7张图片

这张图是对以上五种IO模型的汇总比较,总的来说,越靠后的模型在理论上来说就越高效。

前面的四种IO模型【阻塞IO、非阻塞IO、IO多路复用、信号驱动IO】,都属于同步IO,只有最后一种模型是真正的异步【异步IO】

系统调用介绍

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

因为select是轮询的模式,不停的检查文件句柄的状态。

epoll是callback的模式,当文件句柄准备好了之后,直接进行回调,更高效。

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

在Windows系统下,通过IOCP实现。

在Linux系统下,没有,因为Linux系统下的AIO底层仍是epoll。

(个人猜测,这也是为什么Netty使用了NIO,而没有使用AIO)

他山之石

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

zero-copy

你可能感兴趣的:(unix和Linux的五种io模型,Unix的五种IO模型介绍)